Strategies for detecting player getting stuck

Hey yall, I have a problem in my game with the player sometimes getting stuck inside other objects. Typically when the player is moving really fast they can sort of jam into some of the static meshes I have out in the scene.

Any ideas of how I could detect this state so I can do something about it?

Thanks

Yes. I spent quite a long time on this problem. The secret is…

  1. Store an array of player locations on tick ( if moving, and different, while the moment keys are held ). You can choose how many you store.

  2. The player is stuck when the ‘user’ is pressing a movement key, and the last N locations are the same. You can monitor this, and decide on N.

  3. When the player is stuck, all you have to do is move them backwards through the list of locations until the move keys start working again.

It’s a bit more complicated than this, but that’s basically what I did, and it works. It sounds like it might look really weird, like some sort of ‘rewind’, but it’s only dealing with small differences so it’s not noticeable at all.

It actually did it with rotation and location.

Oh good idea! Thanks I’ll give that a go

1 Like

I found a trick that works pretty decent.

I put a small sphere collider inside my Pawn’s mesh that was smaller than the mesh. Then when my player got jammed inside blocks, the small sphere collider would be triggered and I could tell if the player was stuck. (it would actually detect the players mesh and the other objects the player was stuck in, but I knew the player was stuck if it detected something other than the player’s mesh)

Here’s code to add the sphere collider and the code to check for collisions:

    // in the pawn constructor
    this->CollisionSphere = CreateDefaultSubobject<USphereComponent>(TEXT("CollisionSphere"));
    this->CollisionSphere->InitSphereRadius(10.0f); // Set the radius as needed
    this->CollisionSphere->SetCollisionProfileName(TEXT("OverlapAllDynamic"));
    this->CollisionSphere->AttachToComponent(this->MeshComponent, FAttachmentTransformRules::KeepRelativeTransform);
    this->CollisionSphere->SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Overlap);
    this->CollisionSphere->SetGenerateOverlapEvents(true);

Then you can detect collisions one of two ways:


    TArray<UPrimitiveComponent*> cols;
    this->CollisionSphere->GetOverlappingComponents(cols);
    string isColliding = cols.Num() > 1? "stuck" : "free";

or set this in the constructor this->CollisionSphere->OnComponentBeginOverlap.AddDynamic(this, &APlayerM::handleStuckPlayer); and add this method to your class:


void APlayerM::handleStuckPlayer(class UPrimitiveComponent* OverlappedComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult) {
    
    // // check if player stuck in block
    bool is_stuck_in_block = OtherActor && (OtherActor != this) && OtherComp;
    ...

}

You could affect the object itself, if it detects an object inside it’s bounds it would teleport or push it outside. If there’s just a few specific objects that have this problem it’d be a good strategy, i think maybe also enabling CCD on both the player and the object might prevent this issue from occurring at all, but it could prove expensive if it’s a lot of objects.

Your sphere trick is cool but a bit limiting in the sense that it could trigger when certain projectiles strike the player and it also wouldn’t detect if a part of the player is stuck inside an object that is outside of the sphere.

A similar approach to your sphere trick would be to do a line-trace from the pelvis to the foot or ground, and if the trace hits something between the pelvis and the foot then it is a fairly safe bet the player is stuck inside something.

Depending on how you implement it, it could be cheaper and more effective than the sphere collider trick (by itself a single line trace from the pelvis to the ground would be about as effective as the sphere collider, however you can easily add more traces, one from the left side of the pelvis down to the left foot, right side of the pelvis down to the right foot, and you can also send another trace up from the pelvis to the shoulders as well to cover a wider area)

if more than one trace fires off it’s a safe bet your actor is inside of something, and if one trace fires off for a longer time than 1 second it’s a safe bet your character is partially stuck inside of something.