void ALMPlayerController::RMouseDownSelectTarget() { FHitResult HitRes = FHitResult(); TArray<TEnumAsByte<EObjectTypeQuery>> ObjectType; //只检测一下对象 ObjectType.Add(EOBJECTTYPEQUERY_SELECTACTOR); if (GetHitResultUnderCursorForObjects(ObjectType,false,HitRes)) { if (HitRes.GetComponent() == pCurSelectedComponent) { return; } else { if (pCurSelectedComponent != nullptr) pCurSelectedComponent->SetRenderCustomDepth(false); pCurSelectedComponent = HitRes.GetComponent(); pCurSelectedComponent->SetRenderCustomDepth(true); } } }
void AKIMCharacter::Interact() { if (IsInRoationState && PickedUpItem) { ((AKIMInteractionActor*)PickedUpItem)->LayBack(this); return; } FHitResult outHit; FCollisionQueryParams params; params.AddIgnoredActor(this); params.AddIgnoredActor(PickedUpItem); FVector TraceStart = CameraComponent->GetComponentLocation(); FVector TraceEnd = TraceStart + (CameraComponent->GetForwardVector() * InteractionDistance); GetWorld()->LineTraceSingleByChannel(outHit, TraceStart, TraceEnd, ECollisionChannel::ECC_PhysicsBody, params); if (outHit.GetActor() != NULL && outHit.GetActor()->GetClass()->IsChildOf(AKIMInteractionActor::StaticClass())) { AKIMInteractionActor* InteractionActor = ((AKIMInteractionActor*)outHit.GetActor()); InteractionActor->Interacted(this, outHit.GetComponent()); UE_LOG(LogClass, Warning, TEXT("Interacted with %s"), *outHit.GetActor()->GetName()); UE_LOG(LogClass, Warning, TEXT("(%s)"), *outHit.GetComponent()->GetName()); } else if (outHit.GetActor() == NULL && PickedUpItem) { PickedUpItem->DetachRootComponentFromParent(true); ((AKIMInteractionActor*)PickedUpItem)->Droped(); ((AKIMInteractionActor*)PickedUpItem)->InteractionType = EKIMInteractionTypes::OnPickUp; UE_LOG(LogClass, Warning, TEXT("Droped %s"), *PickedUpItem->GetName()); PickedUpItem = NULL; } }
//USE BUTTON CODE// void APlayerCharacter::ActivateButton() { UPeterAnimInstance* PeterAnimInstance = Cast<UPeterAnimInstance>(GetMesh()->GetAnimInstance()); if (PeterAnimInstance) { PeterAnimInstance->bIsInteracting = true; } if (PhysicsHandleActive) { PhysicsHandleActive = false; } else if (!PhysicsHandleActive) { PhysicsHandleActive = true; } bool TraceSuccess; FHitResult OutHit; //Uses Trace Channel: PlayerTrace TraceSuccess = this->TraceFromSelf(OutHit, 300.f, ECollisionChannel::ECC_GameTraceChannel6); if (TraceSuccess) { AInteractable* InteractableObject = NULL; InteractableObject = Cast<AInteractable>(OutHit.GetActor()); if (Cast<ALiftableBox>(OutHit.GetActor())) { if (PhysicsHandleActive) { PickedUpBox = Cast<ALiftableBox>(OutHit.GetActor()); if (PickedUpBox->bIsAbove(this) && PickedUpBox->CanBeLifted == true) { PhysicsHandler->GrabComponent(OutHit.GetComponent(), OutHit.BoneName, OutHit.Location, true); } } return; } else if (InteractableObject && InteractableObject->GetClass()->IsChildOf(ALightSwitch::StaticClass()) == false) { if (FVector::Dist(GetActorLocation(), InteractableObject->GetActorLocation()) < 250) { InteractableObject->Interact(this); } } } }
void AFP_FirstPersonCharacter::OnFire() { // Play a sound if there is one if (FireSound != NULL) { UGameplayStatics::PlaySoundAtLocation(this, FireSound, GetActorLocation()); } // try and play a firing animation if specified if(FireAnimation != NULL) { // Get the animation object for the arms mesh UAnimInstance* AnimInstance = Mesh1P->GetAnimInstance(); if(AnimInstance != NULL) { AnimInstance->Montage_Play(FireAnimation, 1.f); } } // Now send a trace from the end of our gun to see if we should hit anything APlayerController* PlayerController = Cast<APlayerController>(GetController()); // Calculate the direction of fire and the start location for trace FVector CamLoc; FRotator CamRot; PlayerController->GetPlayerViewPoint(CamLoc, CamRot); const FVector ShootDir = CamRot.Vector(); FVector StartTrace = FVector::ZeroVector; if (PlayerController) { FRotator UnusedRot; PlayerController->GetPlayerViewPoint(StartTrace, UnusedRot); // Adjust trace so there is nothing blocking the ray between the camera and the pawn, and calculate distance from adjusted start StartTrace = StartTrace + ShootDir * ((GetActorLocation() - StartTrace) | ShootDir); } // Calculate endpoint of trace const FVector EndTrace = StartTrace + ShootDir * WeaponRange; // Check for impact const FHitResult Impact = WeaponTrace(StartTrace, EndTrace); // Deal with impact AActor* DamagedActor = Impact.GetActor(); UPrimitiveComponent* DamagedComponent = Impact.GetComponent(); // If we hit an actor, with a component that is simulating physics, apply an impulse if ((DamagedActor != NULL) && (DamagedActor != this) && (DamagedComponent != NULL) && DamagedComponent->IsSimulatingPhysics()) { DamagedComponent->AddImpulseAtLocation(ShootDir*WeaponDamage, Impact.Location); } }
void AMagnetTile::UpdatePortalSearch( AActor* actor , const FHitResult& hit ) { auto portal = Cast<APortalTile>( actor ); if ( portal != nullptr && CanSpawnSubMagnet() ) { auto hitPortalTrigger = hit.GetComponent(); FVector subMagnetTileDir , subMagnetTilePos; portal->GetMagnetPortalTransportedLocation( hitPortalTrigger , subMagnetTileDir , subMagnetTilePos ); SpawnSubMagnet( subMagnetTilePos , subMagnetTileDir ); } }
void UGrabber::Grab() { UE_LOG(LogTemp, Warning, TEXT("Grab!!")); FHitResult hitResult = GetFirstPhysicsBodyInReach(); auto ActorHit = hitResult.GetActor(); if (ActorHit != nullptr) { auto ComponentToGrab = hitResult.GetComponent(); //Try and reach any actors with physics body and then attach them physicsHandle->GrabComponent(ComponentToGrab, NAME_None, ComponentToGrab->GetOwner()->GetActorLocation(), true); } }
///Define the press grab key operation void UGrabber::GrabPressed() { UE_LOG(LogTemp, Warning, TEXT("Grab Pressed!")); // Get the hit object with physical body FHitResult HitObj = FindTheFirstReachingObject(); auto GrabObjComponent = HitObj.GetComponent(); auto GrabObjActor = HitObj.GetActor(); // If hit a object, grab it by using grab component if (GrabObjActor) { PhysicalHandler->GrabComponent( GrabObjComponent, NAME_None, GrabObjComponent->GetOwner()->GetActorLocation(), true ); } }
void AProjectile::SpawnImpactFX(const FHitResult& Hit) { FRandomStream Stream; //random stream FRotator rotTemp = Hit.ImpactNormal.Rotation(); rotTemp = FRotator(rotTemp.Pitch, rotTemp.Yaw, Stream.FRandRange(-180, 180)); //randomly rotate the effect //impact effects sound spawn UGameplayStatics::SpawnEmitterAtLocation(this, ImpactFX.Effect, Hit.ImpactPoint, rotTemp, true); //spawn decal effect on impact position UGameplayStatics::SpawnDecalAttached(ImpactFX.DecalMaterial, FVector(ImpactFX.DecalSize, ImpactFX.DecalSize, 1.0F), Hit.GetComponent(), Hit.BoneName, Hit.ImpactPoint, rotTemp, EAttachLocation::KeepWorldPosition, ImpactFX.DecalHealth); }
UPrimitiveComponent* UPhysicsSpringComponent::GetSpringCollision(const FVector& Start, const FVector& End, float& Time) const { UWorld* World = GetWorld(); AActor* IgnoreActor = bIgnoreSelf ? GetOwner() : nullptr; static FName NAME_Spring = FName(TEXT("SpringComponent")); FCollisionQueryParams QueryParams(NAME_Spring, true, IgnoreActor); FHitResult Hit; UPrimitiveComponent* CollidedComponent = nullptr; const FVector Delta = End - Start; const float DeltaSizeSqr = Delta.SizeSquared(); if (DeltaSizeSqr > FMath::Square(SMALL_NUMBER)) { if (bool bBlockingHit = World->SweepSingleByChannel(Hit, Start, End, FQuat::Identity, SpringChannel, FCollisionShape::MakeSphere(SpringRadius), QueryParams)) { CollidedComponent = Hit.GetComponent(); Time = CollidedComponent ? Hit.Time : 1.f; } } return CollidedComponent; }
EConvertQueryResult ConvertQueryImpactHit(const UWorld* World, const PxLocationHit& PHit, FHitResult& OutResult, float CheckLength, const PxFilterData& QueryFilter, const FVector& StartLoc, const FVector& EndLoc, const PxGeometry* const Geom, const PxTransform& QueryTM, bool bReturnFaceIndex, bool bReturnPhysMat) { SCOPE_CYCLE_COUNTER(STAT_ConvertQueryImpactHit); #if WITH_EDITOR if(bReturnFaceIndex && World->IsGameWorld()) { if(!ensure(UPhysicsSettings::Get()->bSuppressFaceRemapTable == false)) { UE_LOG(LogPhysics, Error, TEXT("A scene query is relying on face indices, but bSuppressFaceRemapTable is true.")); bReturnFaceIndex = false; } } #endif checkSlow(PHit.flags & PxHitFlag::eDISTANCE); const bool bInitialOverlap = PHit.hadInitialOverlap(); if (bInitialOverlap && Geom != nullptr) { ConvertOverlappedShapeToImpactHit(World, PHit, StartLoc, EndLoc, OutResult, *Geom, QueryTM, QueryFilter, bReturnPhysMat); return EConvertQueryResult::Valid; } // See if this is a 'blocking' hit const PxFilterData PShapeFilter = PHit.shape->getQueryFilterData(); const PxQueryHitType::Enum HitType = FPxQueryFilterCallback::CalcQueryHitType(QueryFilter, PShapeFilter); OutResult.bBlockingHit = (HitType == PxQueryHitType::eBLOCK); OutResult.bStartPenetrating = bInitialOverlap; // calculate the hit time const float HitTime = PHit.distance/CheckLength; OutResult.Time = HitTime; OutResult.Distance = PHit.distance; // figure out where the the "safe" location for this shape is by moving from the startLoc toward the ImpactPoint const FVector TraceStartToEnd = EndLoc - StartLoc; const FVector SafeLocationToFitShape = StartLoc + (HitTime * TraceStartToEnd); OutResult.Location = SafeLocationToFitShape; const bool bUsePxPoint = ((PHit.flags & PxHitFlag::ePOSITION) && !bInitialOverlap); if (bUsePxPoint && !PHit.position.isFinite()) { #if ENABLE_NAN_DIAGNOSTIC SetHitResultFromShapeAndFaceIndex(PHit.shape, PHit.actor, PHit.faceIndex, OutResult, bReturnPhysMat); UE_LOG(LogCore, Error, TEXT("ConvertQueryImpactHit() NaN details:\n>> Actor:%s (%s)\n>> Component:%s\n>> Item:%d\n>> BoneName:%s\n>> Time:%f\n>> Distance:%f\n>> Location:%s\n>> bIsBlocking:%d\n>> bStartPenetrating:%d"), *GetNameSafe(OutResult.GetActor()), OutResult.Actor.IsValid() ? *OutResult.GetActor()->GetPathName() : TEXT("no path"), *GetNameSafe(OutResult.GetComponent()), OutResult.Item, *OutResult.BoneName.ToString(), OutResult.Time, OutResult.Distance, *OutResult.Location.ToString(), OutResult.bBlockingHit ? 1 : 0, OutResult.bStartPenetrating ? 1 : 0); #endif // ENABLE_NAN_DIAGNOSTIC OutResult.Reset(); logOrEnsureNanError(TEXT("ConvertQueryImpactHit() received NaN/Inf for position: %.2f %.2f %.2f"), PHit.position.x, PHit.position.y, PHit.position.z); return EConvertQueryResult::Invalid; } OutResult.ImpactPoint = bUsePxPoint ? P2UVector(PHit.position) : StartLoc; // Caution: we may still have an initial overlap, but with null Geom. This is the case for RayCast results. const bool bUsePxNormal = ((PHit.flags & PxHitFlag::eNORMAL) && !bInitialOverlap); if (bUsePxNormal && !PHit.normal.isFinite()) { #if ENABLE_NAN_DIAGNOSTIC SetHitResultFromShapeAndFaceIndex(PHit.shape, PHit.actor, PHit.faceIndex, OutResult, bReturnPhysMat); UE_LOG(LogCore, Error, TEXT("ConvertQueryImpactHit() NaN details:\n>> Actor:%s (%s)\n>> Component:%s\n>> Item:%d\n>> BoneName:%s\n>> Time:%f\n>> Distance:%f\n>> Location:%s\n>> bIsBlocking:%d\n>> bStartPenetrating:%d"), *GetNameSafe(OutResult.GetActor()), OutResult.Actor.IsValid() ? *OutResult.GetActor()->GetPathName() : TEXT("no path"), *GetNameSafe(OutResult.GetComponent()), OutResult.Item, *OutResult.BoneName.ToString(), OutResult.Time, OutResult.Distance, *OutResult.Location.ToString(), OutResult.bBlockingHit ? 1 : 0, OutResult.bStartPenetrating ? 1 : 0); #endif // ENABLE_NAN_DIAGNOSTIC OutResult.Reset(); logOrEnsureNanError(TEXT("ConvertQueryImpactHit() received NaN/Inf for normal: %.2f %.2f %.2f"), PHit.normal.x, PHit.normal.y, PHit.normal.z); return EConvertQueryResult::Invalid; } FVector Normal = bUsePxNormal ? P2UVector(PHit.normal).GetSafeNormal() : -TraceStartToEnd.GetSafeNormal(); OutResult.Normal = Normal; OutResult.ImpactNormal = Normal; OutResult.TraceStart = StartLoc; OutResult.TraceEnd = EndLoc; #if ENABLE_CHECK_HIT_NORMAL CheckHitResultNormal(OutResult, TEXT("Invalid Normal from ConvertQueryImpactHit"), StartLoc, EndLoc, Geom); #endif // ENABLE_CHECK_HIT_NORMAL if (bUsePxNormal && !Normal.IsNormalized()) { // TraceStartToEnd should never be zero, because of the length restriction in the raycast and sweep tests. Normal = -TraceStartToEnd.GetSafeNormal(); OutResult.Normal = Normal; OutResult.ImpactNormal = Normal; } const PxGeometryType::Enum SweptGeometryType = Geom ? Geom->getType() : PxGeometryType::eINVALID; OutResult.ImpactNormal = FindGeomOpposingNormal(SweptGeometryType, PHit, TraceStartToEnd, Normal); // Fill in Actor, Component, material, etc. SetHitResultFromShapeAndFaceIndex(PHit.shape, PHit.actor, PHit.faceIndex, OutResult, bReturnPhysMat); PxGeometryType::Enum PGeomType = PHit.shape->getGeometryType(); if(PGeomType == PxGeometryType::eHEIGHTFIELD) { // Lookup physical material for heightfields if (bReturnPhysMat && PHit.faceIndex != InvalidQueryHit.faceIndex) { PxMaterial* HitMaterial = PHit.shape->getMaterialFromInternalFaceIndex(PHit.faceIndex); if (HitMaterial != NULL) { OutResult.PhysMaterial = FPhysxUserData::Get<UPhysicalMaterial>(HitMaterial->userData); } } } else if (bReturnFaceIndex && PGeomType == PxGeometryType::eTRIANGLEMESH) { PxTriangleMeshGeometry PTriMeshGeom; if( PHit.shape->getTriangleMeshGeometry(PTriMeshGeom) && PTriMeshGeom.triangleMesh != NULL && PHit.faceIndex < PTriMeshGeom.triangleMesh->getNbTriangles() ) { if (const PxU32* TriangleRemap = PTriMeshGeom.triangleMesh->getTrianglesRemap()) { OutResult.FaceIndex = TriangleRemap[PHit.faceIndex]; } } } return EConvertQueryResult::Valid; }
bool UMovementComponent::ResolvePenetrationImpl(const FVector& ProposedAdjustment, const FHitResult& Hit, const FQuat& NewRotationQuat) { // SceneComponent can't be in penetration, so this function really only applies to PrimitiveComponent. const FVector Adjustment = ConstrainDirectionToPlane(ProposedAdjustment); if (!Adjustment.IsZero() && UpdatedPrimitive) { // See if we can fit at the adjusted location without overlapping anything. AActor* ActorOwner = UpdatedComponent->GetOwner(); if (!ActorOwner) { return false; } UE_LOG(LogMovement, Verbose, TEXT("ResolvePenetration: %s.%s at location %s inside %s.%s at location %s by %.3f (netmode: %d)"), *ActorOwner->GetName(), *UpdatedComponent->GetName(), *UpdatedComponent->GetComponentLocation().ToString(), *GetNameSafe(Hit.GetActor()), *GetNameSafe(Hit.GetComponent()), Hit.Component.IsValid() ? *Hit.GetComponent()->GetComponentLocation().ToString() : TEXT("<unknown>"), Hit.PenetrationDepth, (uint32)GetNetMode()); // We really want to make sure that precision differences or differences between the overlap test and sweep tests don't put us into another overlap, // so make the overlap test a bit more restrictive. const float OverlapInflation = CVarPenetrationOverlapCheckInflation.GetValueOnGameThread(); bool bEncroached = OverlapTest(Hit.TraceStart + Adjustment, NewRotationQuat, UpdatedPrimitive->GetCollisionObjectType(), UpdatedPrimitive->GetCollisionShape(OverlapInflation), ActorOwner); if (!bEncroached) { // Move without sweeping. MoveUpdatedComponent(Adjustment, NewRotationQuat, false, nullptr, ETeleportType::TeleportPhysics); UE_LOG(LogMovement, Verbose, TEXT("ResolvePenetration: teleport by %s"), *Adjustment.ToString()); return true; } else { // Disable MOVECOMP_NeverIgnoreBlockingOverlaps if it is enabled, otherwise we wouldn't be able to sweep out of the object to fix the penetration. TGuardValue<EMoveComponentFlags> ScopedFlagRestore(MoveComponentFlags, EMoveComponentFlags(MoveComponentFlags & (~MOVECOMP_NeverIgnoreBlockingOverlaps))); // Try sweeping as far as possible... FHitResult SweepOutHit(1.f); bool bMoved = MoveUpdatedComponent(Adjustment, NewRotationQuat, true, &SweepOutHit, ETeleportType::TeleportPhysics); UE_LOG(LogMovement, Verbose, TEXT("ResolvePenetration: sweep by %s (success = %d)"), *Adjustment.ToString(), bMoved); // Still stuck? if (!bMoved && SweepOutHit.bStartPenetrating) { // Combine two MTD results to get a new direction that gets out of multiple surfaces. const FVector SecondMTD = GetPenetrationAdjustment(SweepOutHit); const FVector CombinedMTD = Adjustment + SecondMTD; if (SecondMTD != Adjustment && !CombinedMTD.IsZero()) { bMoved = MoveUpdatedComponent(CombinedMTD, NewRotationQuat, true, nullptr, ETeleportType::TeleportPhysics); UE_LOG(LogMovement, Verbose, TEXT("ResolvePenetration: sweep by %s (MTD combo success = %d)"), *CombinedMTD.ToString(), bMoved); } } // Still stuck? if (!bMoved) { // Try moving the proposed adjustment plus the attempted move direction. This can sometimes get out of penetrations with multiple objects const FVector MoveDelta = ConstrainDirectionToPlane(Hit.TraceEnd - Hit.TraceStart); if (!MoveDelta.IsZero()) { bMoved = MoveUpdatedComponent(Adjustment + MoveDelta, NewRotationQuat, true, nullptr, ETeleportType::TeleportPhysics); UE_LOG(LogMovement, Verbose, TEXT("ResolvePenetration: sweep by %s (adjusted attempt success = %d)"), *(Adjustment + MoveDelta).ToString(), bMoved); } } return bMoved; } } return false; }
void UShardsMovementComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction) { Super::TickComponent(DeltaTime, TickType, ThisTickFunction); FHitResult HitResult; FHitResult ShapeTraceResult; FCollisionShape shape = FCollisionShape::MakeBox(FVector(0.72f*playerradius, 0.72f*playerradius,10.0f)); FCollisionQueryParams Params; Params.bFindInitialOverlaps = true; Params.AddIgnoredActor(UpdatedComponent->GetAttachmentRootActor()); // Telepads don't count. for (TActorIterator<ATelePad> ActorItr(GetWorld()); ActorItr; ++ActorItr) { Params.AddIgnoredActor(ActorItr.operator->()); } // Neither do destructibles. for (TActorIterator<ADestructibleBox> ActorItr(GetWorld()); ActorItr; ++ActorItr) { // When they're broken, that is. if (ActorItr->fadetimer >= 0.0f) { Params.AddIgnoredActor(ActorItr.operator->()); } } if (isclimbing) { return; } TArray<FHitResult> results; if (forceregiondirection.Z == 0.0f) { GetWorld()->SweepMultiByChannel(results, UpdatedComponent->GetComponentLocation() - 0.0f*45.0f*FVector::UpVector, UpdatedComponent->GetComponentLocation() - 1000.0f*FVector::UpVector, FQuat::Identity, ECC_Visibility, shape, Params); //100 for (FHitResult r : results) { if (r.Normal.Z > 0.6f) { ShapeTraceResult = r; break; } } if (!ShapeTraceResult.IsValidBlockingHit()) { GetWorld()->LineTraceSingleByChannel(ShapeTraceResult, UpdatedComponent->GetComponentLocation(), UpdatedComponent->GetComponentLocation() - 1000.0f*FVector::UpVector, ECC_Visibility, Params); } } FVector PlayerCapsuleBottom = UpdatedComponent->GetComponentLocation() - 45.0f * FVector::UpVector; // 50 float RequiredDistance = (onground ? 50.0f*grounddetecttfudgefactor : 10.0f)*FMath::Pow(playerhalfheight / 90.0f,4.0f) + playerhalfheight/2.0f; //50,1 DistanceFromImpact = (PlayerCapsuleBottom - ShapeTraceResult.ImpactPoint).Z; overground = ShapeTraceResult.IsValidBlockingHit(); FHitResult groundhitresult; GetWorld()->LineTraceSingleByChannel(groundhitresult, UpdatedComponent->GetComponentLocation(), UpdatedComponent->GetComponentLocation() - 10000.0f*FVector::UpVector, ECC_Visibility, Params); groundtracehit = groundhitresult.ImpactPoint; if (!onground) { offGroundTime += DeltaTime; } toosteep = false; if (enforcementtimer >= 0.0f) { enforcementtimer += DeltaTime; toosteep = true; } wasonground = onground; onground = false; prevgroundvelocity = groundvelocity; groundvelocity = FVector::ZeroVector; platformangularfrequency = 0.0f; platformspindir = 1; FloorNormal = FVector::ZeroVector; if ((enforcementtimer < timerlimit && ShapeTraceResult.Normal.Z>0.6f) && DistanceFromImpact < RequiredDistance && !justjumped) { // (PlayerVelocity.Z <= 0.0f || wasonground) if (ShapeTraceResult.Normal.Z < minnormalz) { if (enforcementtimer == -1.0f) { enforcementtimer = 0.0f; } } else { enforcementtimer = -1.0f; } FVector pvel; // Handle moving platforms. if (ShapeTraceResult.GetActor() != nullptr && ShapeTraceResult.GetComponent() != nullptr && ShapeTraceResult.GetComponent()->IsA(UStaticMeshComponent::StaticClass())) { // The motion of a point on a rigid body is the combination of its motion about the center of mass... FVector angvel = FMath::DegreesToRadians((((UStaticMeshComponent*)ShapeTraceResult.GetComponent())->GetPhysicsAngularVelocity())); FVector rr = GetActorLocation() - (((UStaticMeshComponent*)ShapeTraceResult.GetComponent())->GetComponentLocation()); FVector rvel = FVector::CrossProduct(angvel, rr); // ...and the motion of the center of mass itself. FVector cmvel = (((UStaticMeshComponent*)ShapeTraceResult.GetComponent())->GetPhysicsLinearVelocity()); groundvelocity = rvel + cmvel; platformangularfrequency = -angvel.Z; } if ((PlayerVelocity.Z <= groundvelocity.Z || wasonground)) { onground = true; offGroundTime = 0.0f; } } justjumped = false; bool TraceBlocked; FVector newlocation = UpdatedComponent->GetComponentLocation(); FHitResult TraceHitResult; TraceBlocked = GetWorld()->LineTraceSingleByChannel(TraceHitResult, ShapeTraceResult.ImpactPoint + 1.0f*FVector::UpVector, ShapeTraceResult.ImpactPoint - 10.0f*FVector::UpVector, ECC_Visibility,Params); if (TraceHitResult.Normal.Z > minnormalz) { enforcementtimer = -1.0f; } if (onground) { if (TraceBlocked) { newlocation.Z = TraceHitResult.ImpactPoint.Z + playerhalfheight; // 50 GetWorld()->LineTraceSingleByChannel(TraceHitResult, ShapeTraceResult.ImpactPoint + 1.0f*FVector::UpVector, ShapeTraceResult.ImpactPoint - 10.0f*FVector::UpVector, ECC_Visibility,Params); FloorNormal = TraceHitResult.ImpactNormal; } SafeMoveUpdatedComponent(newlocation - UpdatedComponent->GetComponentLocation(), UpdatedComponent->GetComponentRotation(), true, HitResult); SlideAlongSurface(newlocation - UpdatedComponent->GetComponentLocation(), 1.0 - HitResult.Time, HitResult.Normal, HitResult); } };
void ALaser::checkLaserCollisions(float dt) { FHitResult hit; FCollisionQueryParams queryParam; queryParam.bFindInitialOverlaps = false; queryParam.bReturnFaceIndex = true; FCollisionObjectQueryParams objectParam = objectParam.DefaultObjectQueryParam; if ( !canHitBall ) queryParam.AddIgnoredActor( GetWorld()->GetGameState<AProjectTapGameState>()->GetPlayer() ); auto pos = GetActorLocation(); auto rayStart = pos + dir * 5.0f; auto laserVector = dir * length; auto laserEmitter = laserParticle->EmitterInstances[0]; //ray cast to see if laser hits anything GetWorld()->LineTraceSingleByObjectType(hit,rayStart, pos + laserVector, objectParam,queryParam); auto hitActor = hit.Actor.Get(); if (hitActor != nullptr) { currHitPoint = hit.ImpactPoint; if(!laserSparkParticle->bIsActive) laserSparkParticle->ActivateSystem(); //kills ball if laser hits it auto ball = Cast<ABallPawn>(hitActor); if (ball != nullptr) { ball->Kill(); laserEmitter->SetBeamTargetPoint(hit.ImpactPoint, 0); KillSubLaser(); } else { //if not set laser end point laserEmitter->SetBeamTargetPoint(hit.ImpactPoint, 0); bool typeFound = false; //if hits deflective tile then spawn a new laser object auto tile = Cast<ADeflectiveTile>(hitActor); bool isFrame = false; if (tile != nullptr) { typeFound = true; TArray<USceneComponent*> Children; tile->frameCollisionsComponent->GetChildrenComponents(true, Children); for(int i = 0; i < Children.Num() && typeFound ; ++i) { // printonscreen(hit.Component.Get()->GetName()); // printonscreen(Children[i]->GetName()); if(hit.Component.Get() == Children[i]) { typeFound = false; isFrame = true; } } //cut the laser length to make sure new sub laser start doesn't hit the same object if (typeFound && CanSpawnSubLaser()) SpawnSubLaser(hit.ImpactPoint + hit.ImpactNormal * 10.0f, hit.ImpactNormal); } //if sub laser already exists then keep updating its rotation and position auto subLaserExistsHitDeflectiveTile = currentDepth < MAX_DEPTH && nextLaser != nullptr && tile != nullptr; if (subLaserExistsHitDeflectiveTile) { auto incomingVector = hit.ImpactPoint - GetActorLocation(); //if the incoming vector's angle is too small then kill sublasers to avoid laser flickering auto dot = FVector::DotProduct(-incomingVector.GetSafeNormal(), hit.ImpactNormal); auto angle = FMath::RadiansToDegrees(FMath::Acos(dot)); if (angle < 70.0f) { auto newDir = FMath::GetReflectionVector(incomingVector, hit.ImpactNormal); auto start = hit.ImpactPoint + newDir * 2.0f; nextLaser->SetActorLocation(hit.ImpactPoint); nextLaser->dir = newDir.IsNormalized() ? newDir : newDir.GetSafeNormal(); nextLaser->laserParticle->EmitterInstances[0]->SetBeamSourcePoint(hit.ImpactPoint, 0); nextLaser->laserParticle->EmitterInstances[0]->SetBeamTargetPoint(start + newDir * length, 0); } else { KillSubLaser(); } } //if the laser hits turret then kills it if (!typeFound) { auto turret = Cast<ATurretPawn>(hitActor); if (turret != nullptr) { typeFound = true; turret->Damage(2.0f); } } APortalTile* portal = nullptr; if (!typeFound) { portal = Cast<APortalTile>(hitActor); if (CanSpawnSubLaser() && portal != nullptr) { typeFound = true; auto relativePos = hit.ImpactPoint - hit.GetComponent()->GetComponentLocation(); currHitPoint = relativePos + portal->GetActorLocation(); SpawnSubLaser(currHitPoint, hit.ImpactNormal); } } auto subLaserExistsHitPortalTile = currentDepth < MAX_DEPTH && nextLaser != nullptr && portal != nullptr; if (subLaserExistsHitPortalTile) { FVector newSourcePos; portal->GetLaserPortalTransportedLocation(hit.GetComponent(), nextLaser->dir, newSourcePos); nextLaser->SetActorLocation(newSourcePos); nextLaser->laserParticle->EmitterInstances[0]->SetBeamSourcePoint(newSourcePos, 0); nextLaser->laserParticle->EmitterInstances[0]->SetBeamTargetPoint(newSourcePos + nextLaser->dir * length, 0); } bool notHitDeflectiveTile = tile == nullptr || isFrame; bool notHitPortal = portal == nullptr; if (notHitDeflectiveTile && notHitPortal) { KillSubLaser(); } } laserSparkParticle->SetWorldLocation(currHitPoint); laserSparkParticle->SetWorldRotation(FVector(currHitPoint - GetActorLocation()).GetSafeNormal().Rotation().Quaternion()); } else { currHitPoint = laserVector; laserEmitter->SetBeamTargetPoint(pos + currHitPoint, 0); laserSparkParticle->SetWorldLocation( pos + currHitPoint ); laserSparkParticle->SetWorldRotation( FVector( (pos + currHitPoint) - GetActorLocation() ).GetSafeNormal().Rotation().Quaternion() ); KillSubLaser(); } //only root laser can have an emitter mesh if (currentDepth != 0) { //update laser emitter rotation mesh->SetVisibility(false); } else { mesh->SetWorldRotation(dir.Rotation()); } }