What to do after a failed move from SafeMoveUpdatedComponent

I derived a class “UPhysicsBallMovementComponent” from “UMovementComponent”. I would like to implement physics ball movement in this class (without enabling physics simulation on the actor).

I call “SafeMoveUpdatedComponent” in a while loop in the function TickComponent() to move the actor (in multiple small distances).

One difficulty I meet is handling the ball roll/slide a surface. In case that the ball is on a horizontal surface and with an initial velocity (x=100, y=0, z=0), the ball hits the surface very often (because gravity is set to 980) and “SafeMoveUpdatedComponent” returns false in 50%, I don’t know what to do when a move is failed.

The following is some code. PassedTime equals DeltaTime from TickComponent().

FHitResult Hit(1.f);
	const FRotator NewRotation = ActorOwner->GetActorRotation();
	float RemaintingTimeToBeCalculated = PassedTime;
	float CalculateTime = 0.f;
	uint32 Iterations = 0;

	while (RemaintingTimeToBeCalculated > MIN_TICK_TIME && !ActorOwner->IsPendingKill())
	{
		UE_LOG(LogTemp, Warning, TEXT("RemaintingTimeToBeCalculated: %f, PreviousHitTime: %f"), RemaintingTimeToBeCalculated, PreviousHitTime);
		Iterations++;

		CalculateTime = RemaintingTimeToBeCalculated > MAX_TICK_TIME ? MAX_TICK_TIME : RemaintingTimeToBeCalculated; 

		const FVector OldVelocity = Velocity;
		const FVector MoveDelta = ComputeMoveDelta(OldVelocity, CalculateTime);
		bool bMoveResult = SafeMoveUpdatedComponent(MoveDelta, NewRotation, true, Hit);
		//bool bMoveResult = MoveUpdatedComponent(MoveDelta, NewRotation, true, &Hit);
		if (bMoveResult == true)
		{
			UE_LOG(LogTemp, Warning, TEXT("bMoveResult is true"));
		}
		else
		{
			UE_LOG(LogTemp, Warning, TEXT("bMoveResult is false"));
			float SubTickTimeRemaining = CalculateTime;
			Slide(Hit.Normal, SubTickTimeRemaining);
			RemaintingTimeToBeCalculated -= (CalculateTime - SubTickTimeRemaining);
		/*	if (Iterations > 100)
				break;
			else
				continue;*/
		}
		

		// If we hit a trigger that destroyed us, abort.
		if (ActorOwner->IsPendingKill() || HasStoppedSimulation())
		{
			return;
		}

		if (Hit.bBlockingHit)
		{
			UE_LOG(LogTemp, Warning, TEXT(" Velocity: %s, OldVelocity: %s"), *Velocity.ToString(), *OldVelocity.ToString());

			// Only handle the hit if events didn't change velocity (nothing changed in event) during the movement update.
			if (Velocity == OldVelocity)
			{
				float SubTickTimeRemaining = CalculateTime;
				HandleBlockingHit(Hit, CalculateTime, SubTickTimeRemaining);

				RemaintingTimeToBeCalculated -= (CalculateTime - SubTickTimeRemaining);
			}
			else
			{
				// here, we also need to handle Hit.Time < KINDA_SMALL_NUMBER
				if (Hit.Time < KINDA_SMALL_NUMBER)
				{
					RemaintingTimeToBeCalculated -= CalculateTime * 0.5f;;
				}
				else
				{
					RemaintingTimeToBeCalculated -= CalculateTime * Hit.Time;
				}
				PreviousHitTime = Hit.Time;
				PreviousHitNormal = ConstrainNormalToPlane(Hit.Normal);
			}
		}
		else
		{
			if (bIsSliding)
			{
				check(SlideSurfaceNormal.IsZero() == false);
				ComputeRotation(SlideSurfaceNormal, MoveDelta);
			}

			check(Velocity == OldVelocity);
			const FVector NewVelocity = ComputeVelocity(OldVelocity, CalculateTime);
			UpdateVelocity(NewVelocity);

			RemaintingTimeToBeCalculated -= CalculateTime;
			PreviousHitTime = 1.f;
		}
	}

	ActorOwner->AddActorWorldRotation(RotationFromThisFrame);