float UMovementComponent::SlideAlongSurface(const FVector& Delta, float Time, const FVector& Normal, FHitResult& Hit, bool bHandleImpact) { if (!Hit.bBlockingHit) { return 0.f; } float PercentTimeApplied = 0.f; const FVector OldHitNormal = Normal; FVector SlideDelta = ComputeSlideVector(Delta, Time, Normal, Hit); if ((SlideDelta | Delta) > 0.f) { const FQuat Rotation = UpdatedComponent->GetComponentQuat(); SafeMoveUpdatedComponent(SlideDelta, Rotation, true, Hit); const float FirstHitPercent = Hit.Time; PercentTimeApplied = FirstHitPercent; if (Hit.IsValidBlockingHit()) { // Notify first impact if (bHandleImpact) { HandleImpact(Hit, FirstHitPercent * Time, SlideDelta); } // Compute new slide normal when hitting multiple surfaces. TwoWallAdjust(SlideDelta, Hit, OldHitNormal); // Only proceed if the new direction is of significant length and not in reverse of original attempted move. if (!SlideDelta.IsNearlyZero(1e-3f) && (SlideDelta | Delta) > 0.f) { // Perform second move SafeMoveUpdatedComponent(SlideDelta, Rotation, true, Hit); const float SecondHitPercent = Hit.Time * (1.f - FirstHitPercent); PercentTimeApplied += SecondHitPercent; // Notify second impact if (bHandleImpact && Hit.bBlockingHit) { HandleImpact(Hit, SecondHitPercent * Time, SlideDelta); } } } return FMath::Clamp(PercentTimeApplied, 0.f, 1.f); } return 0.f; }
void UFloatingPawnMovement::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction) { Super::TickComponent(DeltaTime, TickType, ThisTickFunction); if (!PawnOwner || !UpdatedComponent || ShouldSkipUpdate(DeltaTime)) { return; } const AController* Controller = PawnOwner->GetController(); if (Controller && Controller->IsLocalController()) { ApplyControlInputToVelocity(DeltaTime); LimitWorldBounds(); bPositionCorrected = false; // Move actor FVector Delta = Velocity * DeltaTime; if (!Delta.IsNearlyZero(1e-6f)) { const FVector OldLocation = UpdatedComponent->GetComponentLocation(); const FRotator Rotation = UpdatedComponent->GetComponentRotation(); FVector TraceStart = OldLocation; FHitResult Hit(1.f); SafeMoveUpdatedComponent(Delta, Rotation, true, Hit); if (Hit.IsValidBlockingHit()) { HandleImpact(Hit, DeltaTime, Delta); // Try to slide the remaining distance along the surface. SlideAlongSurface(Delta, 1.f-Hit.Time, Hit.Normal, Hit, true); } // Update velocity // We don't want position changes to vastly reverse our direction (which can happen due to penetration fixups etc) if (!bPositionCorrected) { const FVector NewLocation = UpdatedComponent->GetComponentLocation(); Velocity = ((NewLocation - OldLocation) / DeltaTime); } } // Finalize UpdateComponentVelocity(); } };
bool UInterpToMovementComponent::HandleHitWall(const FHitResult& Hit, float Time, const FVector& MoveDelta) { AActor* ActorOwner = UpdatedComponent ? UpdatedComponent->GetOwner() : NULL; if (!CheckStillInWorld() || !ActorOwner || ActorOwner->IsPendingKill()) { return true; } HandleImpact(Hit, Time, MoveDelta); if (ActorOwner->IsPendingKill() || !UpdatedComponent) { return true; } return false; }
UProjectileMovementComponent::EHandleBlockingHitResult UProjectileMovementComponent::HandleBlockingHit(const FHitResult& Hit, float TimeTick, const FVector& MoveDelta, float& SubTickTimeRemaining) { AActor* ActorOwner = UpdatedComponent ? UpdatedComponent->GetOwner() : NULL; if (!CheckStillInWorld() || !ActorOwner || ActorOwner->IsPendingKill()) { return EHandleBlockingHitResult::Abort; } HandleImpact(Hit, TimeTick, MoveDelta); if (ActorOwner->IsPendingKill() || HasStoppedSimulation()) { return EHandleBlockingHitResult::Abort; } SubTickTimeRemaining = TimeTick * (1.f - Hit.Time); return EHandleBlockingHitResult::Deflect; }
void CProjectile::HandleTouch(HOBJECT hObj) { if (m_bObjectRemoved) return; // Don't process any touches until this has been cleared... if (m_bProcessInvImpact) return; // Let it get out of our bounding box... if (hObj == m_hFiredFrom) return; CCharacterHitBox* pHitBox = LTNULL; // If we've hit a character (or body), let its hit box take control... if (IsCharacter(hObj)) { CCharacter* pChar = (CCharacter*)g_pLTServer->HandleToObject(hObj); if (pChar) { hObj = pChar->GetHitBox(); } } else if (IsBody(hObj)) { Body* pBody = (Body*)g_pLTServer->HandleToObject(hObj); if (pBody) { hObj = pBody->GetHitBox(); } } if (IsCharacterHitBox(hObj)) { pHitBox = (CCharacterHitBox*)g_pLTServer->HandleToObject(hObj); if (!pHitBox) return; if (pHitBox->GetModelObject() == m_hFiredFrom) return; } // Don't hit our own type of projectiles (for multi-projectile weapons // and projectiles that stick to objects)... if (IsKindOf(hObj, m_hObject)) { CProjectile* pObj = (CProjectile*)g_pLTServer->HandleToObject(hObj); if (pObj) { if (pObj->GetFiredFrom() == m_hFiredFrom) { return; } } } // See if we want to impact on this object... uint32 dwUsrFlags = g_pLTServer->GetObjectUserFlags(hObj); if (dwUsrFlags & USRFLG_IGNORE_PROJECTILES) return; LTBOOL bIsWorld = IsMainWorld(hObj); // Don't impact on non-solid objects...unless it is a CharacterHitBox // object... uint32 dwFlags = g_pLTServer->GetObjectFlags(hObj); if (!bIsWorld && !(dwFlags & FLAG_SOLID)) { if (pHitBox) { // See if we really impacted on the box... if (pHitBox->DidProjectileImpact(this)) { // This is the object that we really hit... hObj = pHitBox->GetModelObject(); } else { return; } } else if (!(dwFlags & FLAG_RAYHIT)) { // If we have ray hit set to true, projectiles should // impact on us too... return; } } // See if we hit the sky... if (bIsWorld || (OT_WORLDMODEL == g_pLTServer->GetObjectType(hObj))) { CollisionInfo info; g_pLTServer->GetLastCollision(&info); SurfaceType eType = GetSurfaceType(info); if (eType == ST_SKY) { RemoveObject(); return; } else if (eType == ST_INVISIBLE) { // Update 1.002 [KLS] - If multiplayer and we hit an invisible // surface, just treat it like a normal surface... if (!IsMultiplayerGame()) { m_bProcessInvImpact = LTTRUE; g_pLTServer->GetObjectPos(m_hObject, &m_vInvisNewPos); g_pLTServer->GetVelocity(m_hObject, &m_vInvisVel); m_vInvisNewPos += (m_vInvisVel * g_pLTServer->GetFrameTime()); // Make sure this new position is inside the world...else // just blow up... if (LT_INSIDE == g_pLTServer->Common()->GetPointStatus(&m_vInvisNewPos)) { return; } } } } HandleImpact(hObj); }