Why is Surface Type returning NULL?

So I’ve managed to fix the crash happening with the switch on the Surface Type but now the Surface Type is returning NULL and I don’t know how to fix it.
Any Ideas?

Player.CPP

//Target is the player reference and Hit is the FHitResult info
//Health is the health component we're accessing using the player reference and HP is teh health value stored in the health component
switch (UGameplayStatics::GetSurfaceType(Hit))
		{
		case SurfaceType1:
			UGameplayStatics::ApplyPointDamage(Target, 50.0f, Hit.TraceStart, Hit, GetInstigatorController(), this, UDamageType::StaticClass());
			GEngine->AddOnScreenDebugMessage(-1, 1.0f, FColor::Green, FString::SanitizeFloat(Target->Health->HP));
			GEngine->AddOnScreenDebugMessage(-1, 1.0f, FColor::Green, FString::Printf(TEXT("SurfaceType: %s"), UGameplayStatics::GetSurfaceType(Hit)));
			break;
		case SurfaceType2:
			UGameplayStatics::ApplyPointDamage(Target, 25.0f, Hit.TraceStart, Hit, GetInstigatorController(), this, UDamageType::StaticClass());
			GEngine->AddOnScreenDebugMessage(-1, 1.0f, FColor::Green, FString::SanitizeFloat(Target->Health->HP));
			GEngine->AddOnScreenDebugMessage(-1, 1.0f, FColor::Green, FString::Printf(TEXT("SurfaceType: %s"), UGameplayStatics::GetSurfaceType(Hit)));
			break;
		default:
			UGameplayStatics::ApplyPointDamage(Target, 5.0f, Hit.TraceStart, Hit, GetInstigatorController(), this, UDamageType::StaticClass());
			GEngine->AddOnScreenDebugMessage(-1, 1.0f, FColor::Green, FString::SanitizeFloat(Target->Health->HP));
			GEngine->AddOnScreenDebugMessage(-1, 1.0f, FColor::Green, FString::Printf(TEXT("SurfaceType: %s"), UGameplayStatics::GetSurfaceType(Hit)));
		}

Currently when the Surface Type is returned in the editor I get: (null), meaning in the switch statement its executing default.

And thanks in advance.

Hello!

I think the issue you are facing is with how to make a switch statement with an enum. So for the Surface Type, what it returns is a EPhysicalSurface (here is the doc). So what you need for a switch statement with an enum is to set it up like this:

switch(UGameplayStatics::GetSurfaceType(Hit))
{
    case EPhysicalSurface::SurfaceType1:
         // something
         break;
    case EPhysicalSurface::SurfaceType2:
        // something
        break;
    default:
        // default something
}

Edit: Nevermind, that was not the issue. What I would try is to check what is UGameplayStatics::GetSurfaceType(Hit) giving you. That could be done by adding

EPhysicalSurface TempSurface = UGameplayStatics::GetSurfaceType(Hit);
switch(TempSurface)
{
  // same as before
}

and place a breakpoint on your editor on the switch statement, your editor should tell you the value of TempSurface. If by any means you can’t place a breakpoint, try adding UE_LOGs on default case, with the TempSurface as a argument.

UE_LOG(LogTemp, Log, TEXT("The surface is %s"), *UEnum::GetValueAsString(TempSurface));

I did as you said and it says TempSurface is SurfaceType_Default even though I’m hitting a surface that’s suppose to be SurfaceType1 or SurfaceType2 both return SurfaceType_Default which is weird.
Any ideas?

And thanks for your reply!

You have to make sure the collision query parameters had the bReturnPhysicalMaterial set to true, otherwise it will always be the default.

If using complex collision, the material is specified by the material shader. If using simple collision, it’s specified by the collision body.

Thanks for the reply but that didn’t fix the issue. It still returns the default surface type. Also what do you mean by the second statement(about the collision)?

Well you need to actually apply a phyiscal material to the surface.

If it’s a complex collision query, you are querying the mesh triangles so you need to make sure all the materials have a physical material set.

If you are querying simple collision, the collision rigid bodies need physical materials applied. For skeletal meshes this is done in the physics asset, for other componets this is done in the component details and/or the mesh asset. The default is none.

This is also somewhat dependant on the Collision Mode of the object, e.g. “Default, UseSimpleAsComplex etc…” - since that may change what you are querying.

What would you suggest I change in the physics asset?

Click through every collision body, and apply a physical material to it.

I did but it still returns null.

This may sound silly, but did you edit the surface types on Project Settings -> Physics -> Physical Surface ?

Looks like that has to be set up in order for it to work.

Yes and for some reason it still returns the default surface type.

The only things I can think of are:

  • Maybe the surface is not set with that surface type.
  • The raycast is not hitting the surface that you want, you could debugdrawline that raycast to see it on the viewport.

I have set the surface type which is still weird that it’s still returning the default one and I have checked with a debug line and it is hitting; and, on top of that the way I set it up it is returning the actor its hitting(done with a debug message). Any ideas what’s going on?

I figured out why it wasn’t working! The only problem now is that I don’t know how to fix it. What was happening was that it was returning the default surface type because it wasn’t colliding with the mesh but with the capsule component. Anyone know how to fix this?

Maybe you could assign different collision channels for that Raycast/Surface and another for the Capsule Component. This may help you with that

I fixed it! The problem was that I was using Use Complex Collision as Simple instead of Use Simple Collision as Complex in the physics asset.

1 Like