When player falls off level, SetActorLocation sends the player flying

I’m creating a game using pure C++ (some blueprints have been used to change small functionality). The game I’m creating is the player takes control of a ball and has to progress through the level and get through several obstacles.

Along the way there are checkpoints so if the player falls off the level, a trigger volume is activated and I have used SetActorLocation(), I have also tried TeleportTo(), on the ball to teleport it back to the last checkpoint they triggered.

The problem I’m facing is when the ball is teleported back to the checkpoint, it sends the ball high into the air (I believe it actually moves the actor to the location and it bounces off the floor which then sends it flying but it also looks like it comes flying up from the checkpoint). How can I get around this so that the actor is just placed at the desired location? The problem is in the Death.cpp when its sets the actor location.

When the player goes over a checkpoint Respawn.cpp is triggered.

Respawn.cpp

void URespawn::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
	Super::TickComponent(DeltaTime, TickType, ThisTickFunction);

	if (!Trigger) { return; }

	if (!Ball) { return; }

	// If Actor is on checkpoint,
	if (Trigger->IsOverlappingActor(TriggeringActor)) {
		Ball->SetSpawnLocation(GetOwner()->GetActorLocation()); // Set the new spawn location
	}
}

When the player falls off the edge Death.cpp is called.

Death.cpp

void UDeath::PlayerDeath()
{
	if (Ball == nullptr) { return; } // Reference to pawn

	if (Lives == 0) {
		UGameplayStatics::OpenLevel(this, FName("GameOver")); // If player has died too many times, open Game Over screen
	}
	else {
		Ball->SetActorLocation(Ball->GetSpawnLocation()); // Spawn player at checkpoint (**This is where the problem is**)
		Lives--; // Remove a life
	}
}

The pawn gets the location of the checkpoint + 70.f on the Z axis to prevent collision

TP_RollingBall.cpp // Pawn

void ATP_RollingBall::SetSpawnLocation(FVector Location)
{
	SpawnLocation = Location;
}

FVector ATP_RollingBall::GetSpawnLocation()
{
	return SpawnLocation + FVector(0.f, 0.f, 70.0f);
}

Link to the specific problem

Thanks in advance.

You could try calling SetPhysicsLinearVelocity on one of your ball’s components to (0, 0, 0) to stop it from moving once you set it to its’ new location.

Another idea is to instead spawn a new ball at the spawn point, then possess that ball, and then destroy the old ball that fell off the cliff. This should be doable in the Death.cpp.

When you call SetActorLocation the internal velocity is updated to match the location distance per delta time. You can call the extended version of this function to avoid this behavior, like this:

FHitResult Hit;
Ball->SetActorLocation(Ball->GetSpawnLocation(), false, &Hit, ETeleportType::TeleportPhysics);

By using ETeleportType::TeleportPhysics the velocity isn’t updated. It’s possible that the ball remains its downward velocity, but then you can use RoboScorpion’s solution (+1).

I don’t know if you can pass NULL for the FHitResult, but it’s worth trying it to avoid the unneeded allocation.

Thanks, I forgot to mention that initially I did actually destroy the player and have the controller possess the new pawn but that required changing the other classes to constantly check for the current pawn. Will check out the link though

Thanks, will give this a go

Tried this, no compilation issues when setting FHitResult to NULL FYI but the problem was still there.

Thanks man, that solved the issue so the player landed correctly but it revealed a new issue which was, if the player rolls off and the ball is still rolling, when the player “respawns”, the ball will move in the direction the player was rolling when they fell off.

I fixed this issue by using UPrimitiveComponent::SetPhysicsAngularVelocity and setting it to (0, 0, 0) as well.