Ammo box pickup won't work

Been trying to figure this out for hours.

This is the part of the code that isn’t working, and if I remove the if statement the engine crashes.

void AAmmoCrate::OnPickup(class UPrimitiveComponent* HitComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
	AM4A1 *M4 = Cast<AM4A1>(OtherActor);

	if(M4)
	{
		M4->CurrentSpareAmmo += AmmoCount;

		this->Destroy();

		UE_LOG(LogTemp, Warning, TEXT("Picked up"))
	}
}

I have seen a similar system linking the character in here like this

void Apickup_AmmoCrate::OnPickup(class UPrimitiveComponent* HitComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool FromSweep, const FHitResult& SweepResult)
{
	AArea53Character *character = Cast<AArea53Character>(OtherActor);

	if (character)
	{
		character->ammoPool = character->ammoPool + count;

		this->Destroy();
	}
}

However i have set my defaults in the M4A1.h/cpp files in order not to clutter the character.h/cpp files.

Any help would be much appreciated, cheers!

It sounds like your cast is failing, which is causing your M4 pointer to be null.

This is why, when you remove the if condition, the engine crashes: without the if, your…

M4->CurrentSpareAmmo += AmmoCount;

…line is being executed no matter what. And since M4 is null, the engine crashes due to a null pointer exception.

You should definitely keep using the if statement to prevent this crash, but to solve your problem you need to figure out why your call of Cast<AM4A1>(OtherActor) is failing and returning nullptr every time.

The most likely explanation is, the actor that is triggering the OnPickup(…) event is not an M4A1 actor. More likely, the player’s Pawn is triggering the OnPickup(…) event, when the player moves over to the pickup’s location.

You can test this by changing your cast to your player’s Pawn class. If the cast succeeds, have some debug text let you know. Alternatively, you can use something like the following to find out which actor in particular triggered the event, no matter which type of actor it is:

UE_LOG(LogTemp, Warning, TEXT("Name of actor that triggered OnPickup event = %s"), *AActor::GetDebugName(OtherActor));

If indeed it’s the player’s pawn that’s triggering the event, you probably can’t just cast from the pawn to your M4A1 class, because those two classes are almost certainly not related. Instead, what you can try is somehow getting access to the M4A1 actor through your pawn class. For instance, if your custom pawn class were to have a pointer variable that stores the player’s current weapon, you could make a function on your pawn class that returns this pointer. Then, assuming the returned pointer isn’t null, you could call your “add ammo” code using that pointer.

I hope that makes sense.

Oh, in case it’s not clear, there are plenty of normal reasons why a cast like the one you’re using should fail. For example, let’s say your game has a grenade actor that’s thrown around by players. If someone were to throw a grenade onto the location of your pickup, and the overlap causes the OnPickup(…) event to get called, you should expect the cast to fail to convert the grenade into your target class — because grenades can’t pick up pickups! This would be normal and desired behavior. In other words, just because I say “cast failed” doesn’t necessarily mean there’s a problem. It’s only a problem when the cast never succeeds.