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.
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.
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.
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 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).
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.
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.
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):