Download

Unreal Engine 4.13 (and 4.12) broke my Grenade behaviour!

Hi.

This is frustrating… I come from 4.10 and I had to upgrade due to API changes.

I tried on 4.12 and on 4.13, my Grenade is broken.

You can find the original post on this page in the post number #66

There’s also a video.

It’s about grenade explosions.

Check it out, please and let me know how I can solve!

Instead of posting a video that tells us nothing, how about you tell us how you are tracking the time with those grenades?

What do you mean by tracking the time?

Granades are supposed to explode after X seconds

Do you want to see how I do that?



void AGrenade::BeginPlay()
{
	Super::BeginPlay();

	// This line can't be executed only on the server
	OnActorBeginOverlap.AddDynamic(this, &AGrenade::ApplyFullDamage);

	if (Role < ROLE_Authority)
		return;

	/* TRIGGER TIMER FOR THE PROJECTILE LIFETIME EXPLOSION */
	FTimerDelegate ExplosionDelegate = FTimerDelegate::CreateLambda(=]()
	{
		// Detonate without ignoring anyone
		Explode(TArray<AActor*>());
	});

	GetWorldTimerManager().SetTimer(ExplosionTimer, ExplosionDelegate, ProjectileLifeTime, false);	
}


Keep in mind that this code works with 4.10, but doesn’t since 4.12

UP!!!

You should add traces / log to your code to determine what’s going on.
With those traces, you could see if the problem is because the timer does not trigger or that the grenade does not want to explode.

I already added some logs to figure it out… the timer is always triggered.
Also, the Explode() function is always called.

But I don’t know why… it doesn’t want to explode.

What does that Explode functions do?

It applies a radial damage in the point where the grenade currently is and then triggers an explosion FX.
Then, sets the bExploded frag to true



void AProjectile_Explosives::Explode(const TArray<AActor*>& toIgnore)
{	
        // Always printed!
	if (GEngine) GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("FUNCTION CALLED")));

	if (bExploded || Role < ROLE_Authority)
		return;

	if (ExplosionDamage > 0 && ExplosionRadius > 0 && DamageType)
		UGameplayStatics::ApplyRadialDamage(this, ExplosionDamage, GetActorLocation(), ExplosionRadius, DamageType, toIgnore, nullptr, OwnerWeapon->GetWeaponOwner()->GetController());

	ShowExplosion(FHitResult(), GetActorLocation());

	bExploded = true;
}


Keep adding logs until you find something wrong.

I found what’s wrong… but I can’t understand why it happens

The wrong thing is that sometimes the ShowExplosion() function **is not triggered **

Keep in mind that the** Explode()** function is always executed.
Inside that function, everything works: even the UGameplayStatics::ApplyRadialDamage() is called and the damage is eventually taken from the players around the grenade.

Again, the problem here is just the ShowExplosion() function which doesn’t even get called!

I don’t know why though… this used to work in UE4.10

My guess is that you are not initializing bExploded to zero/false/null in the constructor, and thus, sometimes, your object ends up allocated in some area of memory with previous data in it, and the grenade thinks it’s already exploded.

Nope, it’s initialized to false

Still no able to figure out what’s wrong with the Engine…

#up

You say Explode() is called but ShowExplosion() sometimes isn’t. When you expect something to work but it doesn’t, it means there is a difference between your expectations and whats actually happening. What you should do then is test and confirm your expectations. When something never works, you can use Visual Studio breakpoints. When something “sometimes” doesn’t work, use logging and try to catch the bug in the act. So like someone else said, add logging messages between the lines in Explode(). Here I can do it for you even:



void AProjectile_Explosives::Explode(const TArray<AActor*>& toIgnore)
{	
	UE_LOG(LogTemp, Warning, TEXT("Explode() called"));
    // Always printed!
	if (GEngine) GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("FUNCTION CALLED")));

	UE_LOG(LogTemp, Warning, TEXT("Pre check 1"));
	if (bExploded || Role < ROLE_Authority)
		return;
	UE_LOG(LogTemp, Warning, TEXT("Post check 1"));

	UE_LOG(LogTemp, Warning, TEXT("Pre check 2"));
	if (ExplosionDamage > 0 && ExplosionRadius > 0 && DamageType)
		UGameplayStatics::ApplyRadialDamage(this, ExplosionDamage, GetActorLocation(), ExplosionRadius, DamageType, toIgnore, nullptr, OwnerWeapon->GetWeaponOwner()->GetController());
	UE_LOG(LogTemp, Warning, TEXT("Post check 2"));

	UE_LOG(LogTemp, Warning, TEXT("Pre ShowExplosion()"));
	ShowExplosion(FHitResult(), GetActorLocation());
	UE_LOG(LogTemp, Warning, TEXT("Post ShowExplosion()"));
	
	bExploded = true;
	UE_LOG(LogTemp, Warning, TEXT("Explode() finished"));
}


Now catch it in the act. Try to get the grenade to not explode, while it should. Then check the log, did all the messages print as expected? If not, what messages are missing will give you some useful info. If they do all fire, it means ShowExplosion is called, but that function itself isn’t behaving like you expect.

Also, you should learn to not get hung up on arguments like “it used to work in 4.10”. Things can occur together but that doesn’t mean one implies the other. It only distracts you from finding the real issue. Ok, enough channeling Mr. Miyagi for one day. :stuck_out_tongue:

I don’t get that

Yes, all UE_LOG messages are sent to the Output Log

eee.jpg

As you can see, the ShowExplosion() function DOES GET called, but the code inside of it is not executed… like it’s ignored.

So the problem is inside the ShowExplosion() function. So, now do the same as with AProjectile_Explosives() - logs between all lines in the function.
One question: after the grenade explodes, what happens, I mean, what process do you use to remove it from the scene?

Does your grenade class have a subclass that overrides ShowExplosion() but forgets to call Super::ShowExplosion()? Or if you override it in a blueprint, does it call Parent: ShowExplosion?

No, it doesn’t

I added UE_LOGs to ShowExplosion() as well.

I tried firing two grenades. The first one exploded, the second one didn’t. And so this is the LOG:

First grenade LOG (exploded)



LogTemp:Warning: Explode() called
LogTemp:Warning: Pre check 1
LogTemp:Warning: Post check 1
LogTemp:Warning: Pre check 2
LogTemp:Warning: Post check 2
LogTemp:Warning: Pre ShowExplosion()
LogTemp:Warning: ShowExplosion() called           // <---- oh, that happened!
LogTemp:Warning: CHECK 1 PASSED
LogTemp:Warning: CHECK 2 PASSED AS WELL
LogTemp:Warning: Post ShowExplosion()
LogTemp:Warning: Explode() finished
LogTemp:Warning: ShowExplosion() called           // <---- WHAT??? It happened again?!
LogTemp:Warning: CHECK 1 PASSED
LogTemp:Warning: CHECK 2 PASSED AS WELL


Second grenade LOG (didn’t explode)



LogTemp:Warning: Explode() called
LogTemp:Warning: Pre check 1
LogTemp:Warning: Post check 1
LogTemp:Warning: Pre check 2
LogTemp:Warning: Post check 2
LogTemp:Warning: Pre ShowExplosion()
LogTemp:Warning: Post ShowExplosion()
LogTemp:Warning: Explode() finished


As you can see, the difference is pretty obvious.

In the first log, after


Pre ShowExplosion()

, the ShowExplosion UE_LOGs are getting printed.

In the second log, after


Pre ShowExplosion()

there quickly comes


Post ShowExplosion()

with no trace of the execution of the ShowExplosion() function.

As for the fact that the ShowExplosion() is called twice in the second log, I think (but not sure) it has something to do with my multiplayer. Because I was running server+client

Is ShowExplosion() a replicated function?

Can you show the implementation of ShowExplosion as well?

ShowExplosion is a UFUNCTION(Reliable, NetMulticast)

And this is the implementation




	UE_LOG(LogTemp, Warning, TEXT("ShowExplosion() called"));

	if (ExplosionTemplate)
	{
		UE_LOG(LogTemp, Warning, TEXT("CHECK 1 PASSED"));

		FTransform const SpawnTransform(HitResult.ImpactNormal.Rotation(), Location);
		AExplosionEffect* const EffectActor = GetWorld()->SpawnActorDeferred<AExplosionEffect>(ExplosionTemplate, SpawnTransform);

		if (EffectActor)
		{
			UE_LOG(LogTemp, Warning, TEXT("CHECK 2 PASSED AS WELL"));

			EffectActor->SurfaceHit = HitResult;
			UGameplayStatics::FinishSpawningActor(EffectActor, SpawnTransform);
		}
		
		else
			if (GEngine) GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("EffectActor not valid!")));
	}

	else
		if (GEngine) GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("ExplosionTemplate not valid!")));

	// once exploded... goodbye...
	this->Destroy();