How to get the surface type, and physical material with a projectile in C++?(No Linetraces)

I am trying to use a projectile to get the surface type of a wall or any other actor and for some reason the hit within the function causes the engine to crash when trying to get the surface type and to apply a decal.

void ABullet::BulletHit(UPrimitiveComponent* HitComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit)
{
if (AActor* Actor = Cast<AActor>(Hit.GetActor()))
{
FVector DecalSize(10.0f, 10.0f, 10.0f);
FRotator DecalRotation = Hit.Location.Rotation();
FVector DecalLocation = Hit.Location;
//Checking to see if the surfacetype is equal to the hit result type.
   ..//This does not work.
if (UGameplayStatics::GetSurfaceType(Hit) == SurfaceType5)
{
UGameplayStatics::SpawnDecalAtLocation(Actor, WallDamage, DecalSize, DecalLocation, RandomDecalRotation);
}
//Another method that can be used with linetraces.
  //This method does not work. Engine crashes.
switch(Hit.PhysicalMaterial->SurfaceType)
 {
   case SurfaceType1:
 UGameplayStatics::SpawnDecalAtLocation(Actor, WallDamage, DecalSize, DecalLocation,    RandomDecalRotation);
                      break;
              }
	}
}

Here is the blueprint equivalent of what I am trying to accomplish but it does not work in cpp for some reason.

There’s a mistake I’ve made before when converting code from Blueprint to C++ or vice versa – and thus recreating things – where I forget to enable “Return Material on Move” on the collision object when recreating something. (In your case, presumably the USphereComponent on your ABullet.)

If that’s not set, the hit result will simply not contain any material, period. I tore my hair out for a while over that one at one point.

That may not be your problem here, but it would be the first thing I’d double-check. Just to rule it out as the cause, if nothing else.

1 Like

I have done that and still for some reason the sphere comp doesn’t return a hit in cpp but in bp it works just fine. Thank you for the advice though.

I did as you said and i guess the reason why the engine was crashing is because the hit was returning nullptr. I am not completely sure though.

The decals are firing yet… This line of code would have me believe that it is returning a NULL value even with Return Material On Move checked.

               if (Hit.PhysMaterial->SurfaceType == NULL)
		{
			UE_LOG(LogTemp, Warning, TEXT("Engine Crashed due to null ptr"));
		}

Not all materials have a physical material. If you try to dereference a null physical material (such as on the line switch(Hit.PhysicalMaterial->SurfaceType)) then C++ will crash.
Blueprint has special code in its implementation to test every possible pointer and “do nothing” if it’s null.

1 Like

I have placed physical materials on all of my materials.

I completely understand it is just in order for this to work I need to have no nullptrs. I have placed physical mats on the materials and set the surface type with Return Material On Move checked.

I am just trying to control the issue here I just don’t understand why it is null.

if (Hit2.bBlockingHit)
{
if (Hit.PhysMaterial->SurfaceType == NULL)
{
     UE_LOG(LogTemp, Warning, TEXT("Engine Crashed due to null ptr"));
}
else
{
switch(Hit.PhysicalMaterial->SurfaceType)
 {
   UE_LOG(LogTemp, Warning, TEXT("Not NULL the decal has spawned."));
   case SurfaceType1:
 UGameplayStatics::SpawnDecalAtLocation(Actor, WallDamage, DecalSize, DecalLocation,    RandomDecalRotation);
                      break;
              
	}
}
}

Maybe you didn’t actually hit any surface?

You should be able to stop in the debugger right before you call the line trace function, and step through it, to see what it’s finding.

1 Like

I am not using a linetrace function I am using the Hit result that you get from colliding with the sphere comp. I am trying to get the hitresult information from a on hit event. I am not using a linetrace.

void ABullet::BulletHit(UPrimitiveComponent* HitComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, //I am using this parameter-> const FHitResult& Hit)
{
}

I did hit a surface I see the sphere comp colliding with the wall, and it returns a hit when the bullet hits my character. If the bullet didn’t collide I wouldn’t be able to get a nullptr value from the hit parameter. (Bullet as in sphere comp).

I am getting a blocking hit because I encapsulated the the NULL check and the switch with a blocking hit check.

if (Hit.bBlockingHit)
{
if (Hit.PhysMaterial->SurfaceType == NULL)
  {
     UE_LOG(LogTemp, Warning, TEXT("Engine Crashed due to null ptr"));
  }
 else
  {
    FVector DecalSize2(10.0f, 10.0f, 10.0f);
    FRotator DecalRotation= Hit.ImpactNormal.Rotation();
    FVector DecalLocation= Hit.ImpactPoint;
   switch(Hit.PhysicalMaterial->SurfaceType)
   {
   UE_LOG(LogTemp, Warning, TEXT("Not NULL the decal has spawned."));
   case SurfaceType1:
UGameplayStatics::SpawnDecalAtLocation(Actor, WallDamage, DecalSize, DecalLocation, DecalRotation);
 break;
              
	}
   }
}

If there is a better way to get the surface type please share if possible.

Brief correction: you need to set the collision object with Return Material on Move – i.e., the thing hitting the material – rather than the surface with which you are colliding.

(Which doesn’t feel super intuitive at first glance.)

I note this just because of the way that was phrased, just in case you’d only set it on the thing being hit.

1 Like

I did as you said. The decal is now spawning but the crash is still prevalent on occasions.

If you’re using rigid body collision notifications, then the proxy/simplified collision shapes also need to have collision materials assigned, separate from the mesh materials. Check if perhaps some of yours don’t have materials?

If you’ve covered all three of these variants for each of your simple/proxy collision shapes, then I don’t have any good idea for why the material may come back null.

1 Like

This is referring to the object I am hitting correct? Not the projectile I am using.

I did exactly as u said.

You would have to use a trace of some kind, so if you don’t want to do a line trace, then you would use a sphere trace from the hit location of the projectile. Here’s an example of what I put together (of course I’m using blueprints, but it’s the same basic principle):

1 Like