void FSceneView::DeprojectScreenToWorld(const FVector2D& ScreenPos, const FIntRect& ViewRect, const FMatrix& InvViewMatrix, const FMatrix& InvProjectionMatrix, FVector& out_WorldOrigin, FVector& out_WorldDirection) { int32 PixelX = FMath::TruncToInt(ScreenPos.X); int32 PixelY = FMath::TruncToInt(ScreenPos.Y); // Get the eye position and direction of the mouse cursor in two stages (inverse transform projection, then inverse transform view). // This avoids the numerical instability that occurs when a view matrix with large translation is composed with a projection matrix // Get the pixel coordinates into 0..1 normalized coordinates within the constrained view rectangle const float NormalizedX = (PixelX - ViewRect.Min.X) / ((float)ViewRect.Width()); const float NormalizedY = (PixelY - ViewRect.Min.Y) / ((float)ViewRect.Height()); // Get the pixel coordinates into -1..1 projection space const float ScreenSpaceX = (NormalizedX - 0.5f) * 2.0f; const float ScreenSpaceY = ((1.0f - NormalizedY) - 0.5f) * 2.0f; // The start of the raytrace is defined to be at mousex,mousey,1 in projection space (z=1 is near, z=0 is far - this gives us better precision) // To get the direction of the raytrace we need to use any z between the near and the far plane, so let's use (mousex, mousey, 0.5) const FVector4 RayStartProjectionSpace = FVector4(ScreenSpaceX, ScreenSpaceY, 1.0f, 1.0f); const FVector4 RayEndProjectionSpace = FVector4(ScreenSpaceX, ScreenSpaceY, 0.5f, 1.0f); // Projection (changing the W coordinate) is not handled by the FMatrix transforms that work with vectors, so multiplications // by the projection matrix should use homogeneous coordinates (i.e. FPlane). const FVector4 HGRayStartViewSpace = InvProjectionMatrix.TransformFVector4(RayStartProjectionSpace); const FVector4 HGRayEndViewSpace = InvProjectionMatrix.TransformFVector4(RayEndProjectionSpace); FVector RayStartViewSpace(HGRayStartViewSpace.X, HGRayStartViewSpace.Y, HGRayStartViewSpace.Z); FVector RayEndViewSpace(HGRayEndViewSpace.X, HGRayEndViewSpace.Y, HGRayEndViewSpace.Z); // divide vectors by W to undo any projection and get the 3-space coordinate if (HGRayStartViewSpace.W != 0.0f) { RayStartViewSpace /= HGRayStartViewSpace.W; } if (HGRayEndViewSpace.W != 0.0f) { RayEndViewSpace /= HGRayEndViewSpace.W; } FVector RayDirViewSpace = RayEndViewSpace - RayStartViewSpace; RayDirViewSpace = RayDirViewSpace.GetSafeNormal(); // The view transform does not have projection, so we can use the standard functions that deal with vectors and normals (normals // are vectors that do not use the translational part of a rotation/translation) const FVector RayStartWorldSpace = InvViewMatrix.TransformPosition(RayStartViewSpace); const FVector RayDirWorldSpace = InvViewMatrix.TransformVector(RayDirViewSpace); // Finally, store the results in the hitcheck inputs. The start position is the eye, and the end position // is the eye plus a long distance in the direction the mouse is pointing. out_WorldOrigin = RayStartWorldSpace; out_WorldDirection = RayDirWorldSpace.GetSafeNormal(); }
void UTankAimingComponent::AimAt(const FVector& HitLocation) { AActor* const Owner = GetOwner(); if (IsInitialised()) { FVector OutLaunchVelocity; FVector StartLocation = Barrel->GetSocketLocation(FName(TEXT("Projectile"))); // Only for DebugTrace purpose - if not ignore them FCollisionResponseParams DummyParams; TArray<AActor*> DummyIgnores; // Calculate the OutLaunchVelocity bool bHaveAimSolution = UGameplayStatics::SuggestProjectileVelocity ( this, OutLaunchVelocity, StartLocation, HitLocation, LaunchSpeed, false, 10.f, 0.f, ESuggestProjVelocityTraceOption::DoNotTrace //, DummyParams, DummyIgnores, true // comment line to remove Debug DrawLine ); if (bHaveAimSolution) { AimForwardDirection = OutLaunchVelocity.GetSafeNormal(); MoveBarrelTowards(AimForwardDirection); } } }
void UTankAimingComponent::AimAt(FVector HitLocation, float LaunchSpeed) { if (!Barrel) { return; } FVector OutLaunchVelocity; FVector StartLocation = Barrel->GetSocketLocation(FName("Projectile")); //FVector AimDirection; bool bHaveAimSolution = UGameplayStatics::SuggestProjectileVelocity ( this, OutLaunchVelocity, StartLocation, HitLocation, LaunchSpeed, false, 0, 0, ESuggestProjVelocityTraceOption::DoNotTrace // Paramater must be present to prevent bug ); auto timestamp = GetWorld()->GetTimeSeconds(); if (bHaveAimSolution) { FVector AimDirection = OutLaunchVelocity.GetSafeNormal(); MoveBarrelTowards(AimDirection); //UE_LOG(LogTemp, Warning, TEXT("%f: We're aiming"), timestamp); } }
void UTankAimingComponent::AimAt(FVector HitLocation, float LaunchSpeed) { if (!Barrel) { return; } FVector OutLaunchVelocity; FVector StartLocation = Barrel->GetSocketLocation(FName("End")); bool bHasAimSolution = UGameplayStatics::SuggestProjectileVelocity( this, OutLaunchVelocity, StartLocation, HitLocation, LaunchSpeed, false, 0, 0, ESuggestProjVelocityTraceOption::DoNotTrace ); if (bHasAimSolution) { auto AimDirection = OutLaunchVelocity.GetSafeNormal(); MoveBarrelTowards(AimDirection); } return; }
void AMMO_Character::ShootArrow() { if(Role<ROLE_Authority) ArrowsLeft--; FActorSpawnParameters spawnParams; spawnParams.Owner = this; spawnParams.Instigator = Instigator; FVector SpawnLoc = FVector(0); FVector DirHelper = FVector(0); if (LockedTarget) { SpawnLoc = Player_SkeletalMeshComponent->GetComponentLocation(); DirHelper = LockedTarget->GetActorLocation() - SpawnLoc; } else { SpawnLoc = ShootingLocation->GetComponentLocation(); DirHelper = LastKnownLocationOfTarget - SpawnLoc; } FRotator SpawnRot = Player_SpringArmComponent->GetComponentRotation() + FRotator(0,-90,0); if(Role == ROLE_Authority) FinalArrowDamage = BaseAttack + FMath::RandRange(AttackBonusMin, AttackBonusMax); AArcherArrow* OurNewObject = GetWorld()->SpawnActor<AArcherArrow>(MyArrowObject, SpawnLoc , SpawnRot, spawnParams); OurNewObject->ApplyForce(ArrowForce, this, DirHelper.GetSafeNormal()); }
void AMagnetTile::PullBall( ABallPawn* ball ) { auto prim = Cast<UPrimitiveComponent>( ball->GetRootComponent() ); UWorld* world = GetWorld(); auto DeltaTime = world->DeltaTimeSeconds; AProjectTapGameState* gameState; if ( world != nullptr && ( gameState = world->GetGameState<AProjectTapGameState>() ) != nullptr && gameState->SetMagnetTile( this ) != this ) { FVector angular = FVector::ZeroVector; prim->SetPhysicsAngularVelocity( angular ); float distanceAtNormal = FVector::DotProduct( ball->GetActorLocation() - GetActorLocation() , GetActorForwardVector() ); FVector normalLoc = ( distanceAtNormal * GetActorForwardVector() ) + GetActorLocation(); FVector normalToBall = ball->GetActorLocation() - normalLoc; float dist = normalToBall.Size(); if ( dist > centerTolerance ) { FVector toAdd = dist * -normalToBall.GetSafeNormal(); toAdd.Z = 0; prim->AddRelativeLocation( toAdd ); } } if ( isVertical ) { attractionSpeed *= verticalForceMultiplier; } float originalSpeed = prim->GetPhysicsLinearVelocity().Size(); float newSpeed = attractionSpeed + originalSpeed; prim->SetPhysicsLinearVelocity(newSpeed * -GetActorForwardVector()); }
bool UTKMathFunctionLibrary::AreLineSegmentsCrossing(FVector pointA1, FVector pointA2, FVector pointB1, FVector pointB2) { FVector closestPointA; FVector closestPointB; int32 sideA; int32 sideB; FVector lineVecA = pointA2 - pointA1; FVector lineVecB = pointB2 - pointB1; bool valid = ClosestPointsOnTwoLines(closestPointA, closestPointB, pointA1, lineVecA.GetSafeNormal(), pointB1, lineVecB.GetSafeNormal()); //lines are not parallel if (valid) { sideA = PointOnWhichSideOfLineSegment(pointA1, pointA2, closestPointA); sideB = PointOnWhichSideOfLineSegment(pointB1, pointB2, closestPointB); if ((sideA == 0) && (sideB == 0)) { return true; } else { return false; } } //lines are parallel else { return false; } }
void UTankAimingComponent::AimAt(FVector HitLocation) { if (!Barrel) { return; } FVector OutLaunchVelocity; FVector StartLocation = Barrel->GetSocketLocation(FName("Projectile")); bool bHaveAimSolution = UGameplayStatics::SuggestProjectileVelocity ( this, OutLaunchVelocity, StartLocation, HitLocation, LaunchSpeed, false, 0, 0, ESuggestProjVelocityTraceOption::DoNotTrace // Paramater must be present to prevent bug ); if (bHaveAimSolution) { AimDirection = OutLaunchVelocity.GetSafeNormal(); MoveBarrelTowards(AimDirection); } // If no solution found do nothing }
void UTankAimingComponent::AimAt(FVector HitLocation) { if (!ensure(Barrel)) { return; } FVector OutLaunchVelocity; FVector StartLocation = Barrel->GetSocketLocation(FName("Projectile"));//This gets the socket location //Calculate the OutLaunchVelocity //The was a porblem with the code, even thought the default value was set we still must //specify the parameter bool bHaveAimSolution = UGameplayStatics::SuggestProjectileVelocity ( this, OutLaunchVelocity, StartLocation, HitLocation, LaunchSpeed, false, 0, 0, ESuggestProjVelocityTraceOption::DoNotTrace //Parameter must be present to prevent bug ); if(bHaveAimSolution) { AimDirection = OutLaunchVelocity.GetSafeNormal(); MoveBarrelTowards(AimDirection); } }
void UTankAimingComponent::AimAt(FVector HitLocation) { if (!ensure(Barrel)) { return; } FVector OutLaunchVelocity; FVector StartLocation = Barrel->GetSocketLocation(FName("Projectile")); //calculate the OutLaunchVelocity bool bHaveAimSolution = UGameplayStatics::SuggestProjectileVelocity ( this, OutLaunchVelocity, StartLocation, HitLocation, LaunchSpeed, false, 0, 0, ESuggestProjVelocityTraceOption::DoNotTrace ); if (bHaveAimSolution) { AimDirection = OutLaunchVelocity.GetSafeNormal(); MoveBarrelTowards(AimDirection); } // no aim solution found, do nothing }
void UAnimGraphNode_BoneDrivenController::Draw(FPrimitiveDrawInterface* PDI, USkeletalMeshComponent* SkelMeshComp) const { static const float ArrowHeadWidth = 5.0f; static const float ArrowHeadHeight = 8.0f; const int32 SourceIdx = SkelMeshComp->GetBoneIndex(Node.SourceBone.BoneName); const int32 TargetIdx = SkelMeshComp->GetBoneIndex(Node.TargetBone.BoneName); if ((SourceIdx != INDEX_NONE) && (TargetIdx != INDEX_NONE)) { const FTransform SourceTM = SkelMeshComp->GetSpaceBases()[SourceIdx] * SkelMeshComp->ComponentToWorld; const FTransform TargetTM = SkelMeshComp->GetSpaceBases()[TargetIdx] * SkelMeshComp->ComponentToWorld; PDI->DrawLine(TargetTM.GetLocation(), SourceTM.GetLocation(), FLinearColor(0.0f, 0.0f, 1.0f), SDPG_Foreground, 0.5f); const FVector ToTarget = TargetTM.GetTranslation() - SourceTM.GetTranslation(); const FVector UnitToTarget = ToTarget.GetSafeNormal(); FVector Midpoint = SourceTM.GetTranslation() + 0.5f * ToTarget + 0.5f * UnitToTarget * ArrowHeadHeight; FVector YAxis; FVector ZAxis; UnitToTarget.FindBestAxisVectors(YAxis, ZAxis); const FMatrix ArrowMatrix(UnitToTarget, YAxis, ZAxis, Midpoint); DrawConnectedArrow(PDI, ArrowMatrix, FLinearColor(0.0f, 1.0f, 0.0), ArrowHeadHeight, ArrowHeadWidth, SDPG_Foreground); PDI->DrawPoint(SourceTM.GetTranslation(), FLinearColor(0.8f, 0.8f, 0.2f), 5.0f, SDPG_Foreground); PDI->DrawPoint(SourceTM.GetTranslation() + ToTarget, FLinearColor(0.8f, 0.8f, 0.2f), 5.0f, SDPG_Foreground); } }
void UMovementComponent::TwoWallAdjust(FVector& OutDelta, const FHitResult& Hit, const FVector& OldHitNormal) const { FVector Delta = OutDelta; const FVector HitNormal = Hit.Normal; if ((OldHitNormal | HitNormal) <= 0.f) //90 or less corner, so use cross product for direction { const FVector DesiredDir = Delta; FVector NewDir = (HitNormal ^ OldHitNormal); NewDir = NewDir.GetSafeNormal(); Delta = (Delta | NewDir) * (1.f - Hit.Time) * NewDir; if ((DesiredDir | Delta) < 0.f) { Delta = -1.f * Delta; } } else //adjust to new wall { const FVector DesiredDir = Delta; Delta = ComputeSlideVector(Delta, 1.f - Hit.Time, HitNormal, Hit); if ((Delta | DesiredDir) <= 0.f) { Delta = FVector::ZeroVector; } else if ( FMath::Abs((HitNormal | OldHitNormal) - 1.f) < KINDA_SMALL_NUMBER ) { // we hit the same wall again even after adjusting to move along it the first time // nudge away from it (this can happen due to precision issues) Delta += HitNormal * 0.01f; } } OutDelta = Delta; }
bool UProjectileMovementComponent::HandleSliding(FHitResult& Hit, float& SubTickTimeRemaining) { FHitResult InitialHit(Hit); const FVector OldHitNormal = ConstrainDirectionToPlane(Hit.Normal); // Velocity is now parallel to the impact surface. // Perform the move now, before adding gravity/accel again, so we don't just keep hitting the surface. SafeMoveUpdatedComponent(Velocity * SubTickTimeRemaining, UpdatedComponent->GetComponentQuat(), true, Hit); if (HasStoppedSimulation()) { return false; } // A second hit can deflect the velocity (through the normal bounce code), for the next iteration. if (Hit.bBlockingHit) { const float TimeTick = SubTickTimeRemaining; SubTickTimeRemaining = TimeTick * (1.f - Hit.Time); if (HandleBlockingHit(Hit, TimeTick, Velocity * TimeTick, SubTickTimeRemaining) == EHandleBlockingHitResult::Abort || HasStoppedSimulation()) { return false; } } else { // Find velocity after elapsed time const FVector PostTickVelocity = ComputeVelocity(Velocity, SubTickTimeRemaining); // If pointing back into surface, apply friction and acceleration. const FVector Force = (PostTickVelocity - Velocity); const float ForceDotN = (Force | OldHitNormal); if (ForceDotN < 0.f) { const FVector ProjectedForce = FVector::VectorPlaneProject(Force, OldHitNormal); const FVector NewVelocity = Velocity + ProjectedForce; const FVector FrictionForce = -NewVelocity.GetSafeNormal() * FMath::Min(-ForceDotN * Friction, NewVelocity.Size()); Velocity = ConstrainDirectionToPlane(NewVelocity + FrictionForce); } else { Velocity = PostTickVelocity; } // Check min velocity if (Velocity.SizeSquared() < FMath::Square(BounceVelocityStopSimulatingThreshold)) { StopSimulating(InitialHit); return false; } SubTickTimeRemaining = 0.f; } return true; }
void UTankMovementComponent::RequestDirectMove(const FVector& MoveVelocity, bool bForceMaxSpeed) { auto TankForward = GetOwner()->GetActorForwardVector().GetSafeNormal(); auto AIForwardIntention = MoveVelocity.GetSafeNormal(); auto ForwardThrow = FVector::DotProduct(TankForward, AIForwardIntention); auto RightThrow = FVector::CrossProduct(AIForwardIntention, TankForward); IntendMoveForward(ForwardThrow); IntendTurnRight(RightThrow.GetSafeNormal().Z); }
void AMMO_Character::TakeDamageFromEnemy(int32 Damage, AActor* Monster) { FRotator Rot = Player_SkeletalMeshComponent->GetSocketRotation(TEXT("Head")); Rot = FRotator(0, Rot.Yaw, 0); Rot += FRotator(0, 90, 0); FVector ForwardVector = (Rot.Vector() * 500); FVector DirToGobo = Monster->GetActorLocation() - GetActorLocation(); ForwardVector = FVector(ForwardVector.X, ForwardVector.Y, 0); DirToGobo = FVector(DirToGobo.X, DirToGobo.Y, 0); float DotProduct = FVector::DotProduct(ForwardVector.GetSafeNormal(), DirToGobo.GetSafeNormal()); float Radians = FMath::RadiansToDegrees(acosf(DotProduct)); if (Cast<AMMO_Mob_Character>(Monster)) { Damage = Cast<AMMO_Mob_Character>(Monster)->Attack + FMath::RandRange(Cast<AMMO_Mob_Character>(Monster)->AttackBonusMin, Cast<AMMO_Mob_Character>(Monster)->AttackBonusMax); Multicast_PlaySound(GlobalPool->GenericSoundEffects.FindRef(ESoundEffectLibrary::SFX_DaggerHit), GetActorLocation()); } else if(Cast<ABoss>(Monster)) { Damage = Cast<ABoss>(Monster)->BaseDamage + FMath::RandRange(Cast<ABoss>(Monster)->BonusDamage_Min, Cast<ABoss>(Monster)->BonusDamage_Max); Multicast_PlaySound(GlobalPool->GenericSoundEffects.FindRef(ESoundEffectLibrary::SFX_BossHit), GetActorLocation()); } Damage -= Damage*BaseDamageReduction; if (FMath::Abs(Radians) <= 55.f && bIsShieldBlocking) { Damage = FMath::DivideAndRoundDown(Damage, 3); Multicast_PlayAnimation(GetHurtMontageShield); } else { if (!(AnimInstance->Montage_IsPlaying(AttackMontage) || AnimInstance->Montage_IsPlaying(SecondAttackMontage))) { Multicast_PlayAnimation(GetHurtMontage); } } UpdateHealth(Damage); }
void UDestructibleComponent::ApplyDamage(float DamageAmount, const FVector& HitLocation, const FVector& ImpulseDir, float ImpulseStrength) { #if WITH_APEX if (ApexDestructibleActor != NULL) { const FVector& NormalizedImpactDir = ImpulseDir.GetSafeNormal(); // Transfer damage information to the APEX NxDestructibleActor interface ApexDestructibleActor->applyDamage(DamageAmount, ImpulseStrength, U2PVector( HitLocation ), U2PVector( ImpulseDir )); } #endif }
// Accepts a triangle (XYZ and UV values for each point) and returns a poly base and UV vectors // NOTE : the UV coords should be scaled by the texture size static inline void FTexCoordsToVectors(const FVector& V0, const FVector& UV0, const FVector& V1, const FVector& InUV1, const FVector& V2, const FVector& InUV2, FVector* InBaseResult, FVector* InUResult, FVector* InVResult ) { // Create polygon normal. FVector PN = FVector((V0-V1) ^ (V2-V0)); PN = PN.GetSafeNormal(); FVector UV1( InUV1 ); FVector UV2( InUV2 ); // Fudge UV's to make sure no infinities creep into UV vector math, whenever we detect identical U or V's. if( ( UV0.X == UV1.X ) || ( UV2.X == UV1.X ) || ( UV2.X == UV0.X ) || ( UV0.Y == UV1.Y ) || ( UV2.Y == UV1.Y ) || ( UV2.Y == UV0.Y ) ) { UV1 += FVector(0.004173f,0.004123f,0.0f); UV2 += FVector(0.003173f,0.003123f,0.0f); } // // Solve the equations to find our texture U/V vectors 'TU' and 'TV' by stacking them // into a 3x3 matrix , one for u(t) = TU dot (x(t)-x(o) + u(o) and one for v(t)= TV dot (.... , // then the third assumes we're perpendicular to the normal. // FMatrix TexEqu = FMatrix::Identity; TexEqu.SetAxis( 0, FVector( V1.X - V0.X, V1.Y - V0.Y, V1.Z - V0.Z ) ); TexEqu.SetAxis( 1, FVector( V2.X - V0.X, V2.Y - V0.Y, V2.Z - V0.Z ) ); TexEqu.SetAxis( 2, FVector( PN.X, PN.Y, PN.Z ) ); TexEqu = TexEqu.InverseFast(); const FVector UResult( UV1.X-UV0.X, UV2.X-UV0.X, 0.0f ); const FVector TUResult = TexEqu.TransformVector( UResult ); const FVector VResult( UV1.Y-UV0.Y, UV2.Y-UV0.Y, 0.0f ); const FVector TVResult = TexEqu.TransformVector( VResult ); // // Adjust the BASE to account for U0 and V0 automatically, and force it into the same plane. // FMatrix BaseEqu = FMatrix::Identity; BaseEqu.SetAxis( 0, TUResult ); BaseEqu.SetAxis( 1, TVResult ); BaseEqu.SetAxis( 2, FVector( PN.X, PN.Y, PN.Z ) ); BaseEqu = BaseEqu.InverseFast(); const FVector BResult = FVector( UV0.X - ( TUResult|V0 ), UV0.Y - ( TVResult|V0 ), 0.0f ); *InBaseResult = - 1.0f * BaseEqu.TransformVector( BResult ); *InUResult = TUResult; *InVResult = TVResult; }
void UTankMovementComponent::RequestDirectMove(const FVector & MoveVelocity, bool bForceMaxSpeed) { auto MoveVelocityNormal = MoveVelocity.GetSafeNormal(); auto AIForwardNormal = GetOwner()->GetActorForwardVector().GetSafeNormal(); auto AIRightNormal = GetOwner()->GetActorRightVector().GetSafeNormal(); auto ForwardSpeed = FVector::DotProduct(MoveVelocityNormal, AIForwardNormal);//[-1,1] auto RightSpeed = FVector::DotProduct(MoveVelocityNormal, AIRightNormal);//[-1,1] MoveForward(ForwardSpeed); MoveRight(RightSpeed); }
void UTankMovementComponent::RequestDirectMove(const FVector& MoveVelocity, bool bForceMaxSpeed) { //No reason to call super because we are replacing the functionality auto TankForward = GetOwner()->GetActorForwardVector().GetSafeNormal();//Gets the x vector of the tanks auto AIForwardIntention = MoveVelocity.GetSafeNormal();//safe normal, gets you a normal vertor of of this move velocity with out changing it auto ForwardThrow = FVector::DotProduct(TankForward, AIForwardIntention); // auto RightThrow = FVector::CrossProduct(TankForward, AIForwardIntention).Z;// The sine Function //We ge the z component to get a float IntendMoveForward(ForwardThrow); IntendTurnRight(RightThrow); }
FVector UTKMathFunctionLibrary::ProjectPointOnLine(FVector LineOrigin, FVector LineDirection, FVector Point) { //FVector linePointToPoint = point - linePoint; //float t = FVector::DotProduct(linePointToPoint, lineDir); //return linePoint + lineDir * t; //FVector closestPoint; //OutDistance = FMath::PointDistToLine(point, lineDir, linePoint, closestPoint); //return closestPoint; FVector SafeDir = LineDirection.GetSafeNormal(); return LineOrigin + (SafeDir * ((Point - LineOrigin) | SafeDir)); }
void UTankMovementComponent::RequestDirectMove(const FVector & MoveVelocity, bool bForceMaxSpeed) { // No need to call super as we replacing Parent method FVector TankForward = GetOwner()->GetActorForwardVector().GetSafeNormal(); FVector AIForwardIntention = MoveVelocity.GetSafeNormal(); float ForwardThrow = FVector::DotProduct(TankForward, AIForwardIntention); IntendMoveForward(ForwardThrow); float RightThrow = FVector::CrossProduct(TankForward, AIForwardIntention).Z; IntendTurnRight(RightThrow); }
bool UProjectileMovementComponent::HandleDeflection(FHitResult& Hit, const FVector& OldVelocity, const uint32 NumBounces, float& SubTickTimeRemaining) { const FVector Normal = ConstrainNormalToPlane(Hit.Normal); // Multiple hits within very short time period? const bool bMultiHit = (PreviousHitTime < 1.f && Hit.Time <= KINDA_SMALL_NUMBER); // if velocity still into wall (after HandleBlockingHit() had a chance to adjust), slide along wall const float DotTolerance = 0.01f; bIsSliding = (bMultiHit && FVector::Coincident(PreviousHitNormal, Normal)) || ((Velocity.GetSafeNormal() | Normal) <= DotTolerance); if (bIsSliding) { if (bMultiHit && (PreviousHitNormal | Normal) <= 0.f) { //90 degree or less corner, so use cross product for direction FVector NewDir = (Normal ^ PreviousHitNormal); NewDir = NewDir.GetSafeNormal(); Velocity = Velocity.ProjectOnToNormal(NewDir); if ((OldVelocity | Velocity) < 0.f) { Velocity *= -1.f; } Velocity = ConstrainDirectionToPlane(Velocity); } else { //adjust to move along new wall Velocity = ComputeSlideVector(Velocity, 1.f, Normal, Hit); } // Check min velocity. if (Velocity.SizeSquared() < FMath::Square(BounceVelocityStopSimulatingThreshold)) { StopSimulating(Hit); return false; } // Velocity is now parallel to the impact surface. if (SubTickTimeRemaining > KINDA_SMALL_NUMBER) { if (!HandleSliding(Hit, SubTickTimeRemaining)) { return false; } } } return true; }
void UTankMovementComponent::RequestDirectMove(const FVector & MoveVelocity, bool bForceMaxSpeed) { auto tankForward = GetOwner()->GetActorForwardVector().GetSafeNormal(); auto aiForwardIntention = MoveVelocity.GetSafeNormal(); auto cosThrow = FVector::DotProduct(tankForward, aiForwardIntention); auto sinThrow = FVector::CrossProduct(tankForward, aiForwardIntention).Z; IntendMoveForward(cosThrow); IntendTurnRight(sinThrow); //UE_LOG(LogTemp, Warning, TEXT("cosThrow is %f"), cosThrow); //UE_LOG(LogTemp, Warning, TEXT("sinThrow is %f"), sinThrow); }
bool FVertexSnappingImpl::SnapDragLocationToNearestVertex( const FVector& BaseLocation, FVector& DragDelta, FLevelEditorViewportClient* ViewportClient ) { int32 MouseX = ViewportClient->Viewport->GetMouseX(); int32 MouseY = ViewportClient->Viewport->GetMouseY(); FVector2D MousePosition = FVector2D( MouseX, MouseY ) ; EAxisList::Type CurrentAxis = ViewportClient->GetCurrentWidgetAxis(); bool bSnapped = false; if( !DragDelta.IsNearlyZero() ) { FVector Direction = DragDelta.GetSafeNormal(); FSceneViewFamilyContext ViewFamily(FSceneViewFamily::ConstructionValues( ViewportClient->Viewport, ViewportClient->GetScene(), ViewportClient->EngineShowFlags ) .SetRealtimeUpdate( ViewportClient->IsRealtime() )); FSceneView* View = ViewportClient->CalcSceneView( &ViewFamily ); FVector DesiredUnsnappedLocation = BaseLocation+DragDelta; FBoxSphereBounds SnappingAreaBox( FBox( DesiredUnsnappedLocation-VertexSnappingConstants::MaxSnappingDistance, DesiredUnsnappedLocation+VertexSnappingConstants::MaxSnappingDistance ) ); FBox AllowedSnappingBox = SnappingAreaBox.GetBox(); AllowedSnappingBox += DragDelta; FPlane ActorPlane( DesiredUnsnappedLocation, Direction ); TSet< TWeakObjectPtr<AActor> > NoActorsToIgnore; FVertexSnappingArgs Args ( ActorPlane, DesiredUnsnappedLocation, ViewportClient, View, MousePosition, CurrentAxis, true ); SnapDragDelta( Args, BaseLocation, AllowedSnappingBox, NoActorsToIgnore, DragDelta ); } return bSnapped; }
void UTankMovementComponent::RequestDirectMove(const FVector& MoveVelocity, bool bForceMaxSpeed) { // No need to call super - we are replacing functionality auto TankForward = GetOwner()->GetActorForwardVector().GetSafeNormal(); // Current Heading - unit vector direction relative to the global auto AIForwardIntention = MoveVelocity.GetSafeNormal(); // Direction we WANT to be heading float ForwardVelocity = FVector::DotProduct(TankForward, AIForwardIntention); IntendMoveForward(ForwardVelocity); float RotateVelocity = FVector::CrossProduct(TankForward, AIForwardIntention).Z; IntendTurnRight(RotateVelocity); // auto TankName = GetOwner()->GetName(); // UE_LOG(LogTemp, Warning, TEXT("%s Rotating to: %f"), *TankName, RotateVelocity); }
void ABotController::SetEnemy(class APawn* InPawn) { //Set the blackboard keys to the object and location of the found enemy, for use in the MoveTo behavior tree task BlackboardComp->SetValue<UBlackboardKeyType_Object>(EnemyKeyID, InPawn); BlackboardComp->SetValue<UBlackboardKeyType_Vector>(EnemyLocationID, InPawn->GetActorLocation()); //Calculates and sets the direction for the AI bot's projectile ABot* ThisBot = Cast<ABot>(GetPawn()); ATank *Enemy = Cast<ATank>(this->BestPawn); FVector dir; dir = Enemy->GetActorLocation() - ThisBot->GetActorLocation(); //Finds the vector between the AI bot and the player tank dir = dir.GetSafeNormal(1.0f) * 1000; //Normalizes and scales the vector for a uniform speed ThisBot->Direction = FVector(dir.X, dir.Y, 0.f); //Zeros out the Z value so the projectile moves solely on the horizontal plane }
void UCrowdFollowingComponent::UpdateCachedDirections(const FVector& NewVelocity, const FVector& NextPathCorner, bool bTraversingLink) { // MoveSegmentDirection = direction on string pulled path const FVector AgentLoc = GetCrowdAgentLocation(); const FVector ToCorner = NextPathCorner - AgentLoc; if (ToCorner.SizeSquared() > FMath::Square(10.0f)) { MoveSegmentDirection = ToCorner.GetSafeNormal(); } // CrowdAgentMoveDirection either direction on path or aligned with current velocity if (!bTraversingLink) { CrowdAgentMoveDirection = bRotateToVelocity && (NewVelocity.SizeSquared() > KINDA_SMALL_NUMBER) ? NewVelocity.GetSafeNormal() : MoveSegmentDirection; } }
void UTankAimingComponent::AimAt(FVector HitLocation) { if (!ensure(Barrel)) { return; } FVector OutLaunchVelocity; FVector StartLocation = Barrel->GetSocketLocation(FName("Projectile")); bool bHaveAimSolution = UGameplayStatics::SuggestProjectileVelocity(this, OutLaunchVelocity, StartLocation, HitLocation, LaunchSpeed, false, 0, 0, ESuggestProjVelocityTraceOption::DoNotTrace);//Calculate the OutLauchVelocity if(bHaveAimSolution) { AimDirection = OutLaunchVelocity.GetSafeNormal(); auto Time = GetWorld()->GetTimeSeconds(); //UE_LOG(LogTemp, Warning, TEXT("%f Aim solution found"), Time); MoveBarrelTowards(AimDirection); } else { //if no solution found, do nothing //auto Time = GetWorld()->GetTimeSeconds(); //UE_LOG(LogTemp, Warning, TEXT("%f No solution Found"), Time); } }
void UTankMovementComponent::RequestDirectMove(const FVector & MoveVelocity, bool bForceMaxSpeed) { /*auto AITankName = GetOwner()->GetName();*/ auto TankForward = GetOwner()->GetActorForwardVector().GetSafeNormal(); auto AIForwardIntention = MoveVelocity.GetSafeNormal(); float FwdMove = FVector::DotProduct(TankForward, AIForwardIntention); float Rotate = FVector::CrossProduct(TankForward, AIForwardIntention).Z; if (GetOwner()->FindComponentByClass<UTankAimingComponent>()-> GetFiringStatus() != EFiringStatus::Locked) { IntendMoveForwards(FwdMove); IntendMoveBackwards(FwdMove); IntendRotateCClockwise(Rotate); IntendRotateClockwise(Rotate); } /*UE_LOG(LogTemp, Warning, TEXT("%s moving @ vel %s"), *AITankName, *AIForwardIntention.ToString());*/ }
// Gets a smoothed normal based on the 8 neighbouring vertices FVector FZoneGeneratorWorker::GetNormalFromHeightMapForVertex(const int32 vertexX, const int32 vertexY) { FVector result; int32 rowLength = MyLOD == 0 ? pZoneConfig->XUnits + 1 : (pZoneConfig->XUnits / (FMath::Pow(2, MyLOD)) + 1); int32 heightMapRowLength = rowLength + 2; // the heightmapIndex for this vertex index int32 heightMapIndex = vertexX + 1 + ((vertexY + 1) * heightMapRowLength); // Get the 8 neighbouring points FVector up, down, left, right, upleft, upright, downleft, downright; up = (*pHeightMap)[heightMapIndex + heightMapRowLength] - (*pHeightMap)[heightMapIndex]; down = (*pHeightMap)[heightMapIndex - heightMapRowLength] - (*pHeightMap)[heightMapIndex]; left = (*pHeightMap)[heightMapIndex + 1] - (*pHeightMap)[heightMapIndex]; right = (*pHeightMap)[heightMapIndex - 1] - (*pHeightMap)[heightMapIndex]; upleft = (*pHeightMap)[heightMapIndex + 1 + heightMapRowLength] - (*pHeightMap)[heightMapIndex]; upright = (*pHeightMap)[heightMapIndex - 1 + heightMapRowLength] - (*pHeightMap)[heightMapIndex]; downleft = (*pHeightMap)[heightMapIndex + 1 - heightMapRowLength] - (*pHeightMap)[heightMapIndex]; downright = (*pHeightMap)[heightMapIndex - 1 - heightMapRowLength] - (*pHeightMap)[heightMapIndex]; // Now the eight normals from the triangles this forms FVector n1, n2, n3, n4, n5, n6, n7, n8; n1 = FVector::CrossProduct(left, upleft); n2 = FVector::CrossProduct(upleft, up); n3 = FVector::CrossProduct(up, upright); n4 = FVector::CrossProduct(upright, right); n5 = FVector::CrossProduct(right, downright); n6 = FVector::CrossProduct(downright, down); n7 = FVector::CrossProduct(down, downleft); n8 = FVector::CrossProduct(downleft, left); result = n1 + n2 + n3 + n4 + n5 + n6 + n7 + n8; return result.GetSafeNormal(); }