ToonTanks - Damage registering issues

(for some reason i cannot tag the post to the correct lecture, even when creating the post directly in the lecture)

Hi,

I have problems with damage registering in both tank and turret pawns. I have reached the steps until the UE_LOG in ActorDied function, but no output log of damage applied is shown, wich makes me think damage is not registering, but I cannot find any problems in the code.

Health component is included in both Pawns, and default health is set to 100.0f; I did had the problem in the previous lectures that “AddDynamic” did not work properly if Blueprint class was already existing; I created again the BP thinking it may be the same issue, but no success.

Code for ProjectileBase

#include "ProjectileBase.h"
#include "Components/StaticMeshComponent.h"
#include "GameFramework/ProjectileMovementComponent.h"
#include "Kismet/GameplayStatics.h"


// Sets default values
AProjectileBase::AProjectileBase()
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = false;

	ProjectileMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Projectile Mesh"));
	
	//spawn destruction
	

	RootComponent = ProjectileMesh;

	ProjectileMovement = CreateDefaultSubobject<UProjectileMovementComponent>(TEXT("Projectile Movement"));
	ProjectileMovement->InitialSpeed = MovementSpeed;
	ProjectileMovement->MaxSpeed = MovementSpeed;
	InitialLifeSpan = 3.0f;

}

void AProjectileBase::OnHit(UPrimitiveComponent* HitComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit)
{
	AActor* MyOwner = GetOwner();

	if (!MyOwner) { return; }

	if (OtherActor && OtherActor != this && OtherActor != MyOwner)
	{
		UGameplayStatics::ApplyDamage(OtherActor, Damage, MyOwner->GetInstigatorController(), this, DamageType);
	}

	//play destroy effects

	Destroy();
}

// Called when the game starts or when spawned
void AProjectileBase::BeginPlay()
{
	Super::BeginPlay();
	ProjectileMesh->OnComponentHit.AddDynamic(this, &AProjectileBase::OnHit);
}

Code for TankGameModeBase


void ATankGameModeBase::BeginPlay()
{
	//Get references and game/win lose conditions

	//Call HandleGameStart() to initialise the start countdown, turret activation, pawn check, etc

}

void ATankGameModeBase::ActorDied(AActor* DeadActor)
{
	//check what type of actor died. If turret, tally. If player->go to lose condition

	UE_LOG(LogTemp, Warning, TEXT("A pawn died"));

}

void ATankGameModeBase::HandleGameStart()
{
	//initialise the start countdown, turret activation, pawn check, etc

	//Call blueprint version GameStart()

}

void ATankGameModeBase::HandleGameOver(bool PlayerWon)
{
	//see if player has destroyed all the turrets->show win result if yes

	//else if turret destroyed player->show lose result
	
	//call blueprint version GameOver(bool PlayerWon)

}

Code for HealthComponent

#include "HealthComponent.h"
#include "ToonTanks/GameModes/TankGameModeBase.h"
#include "Kismet/GameplayStatics.h"

// Sets default values for this component's properties
UHealthComponent::UHealthComponent()
{
	// Set this component to be initialized when the game starts, and to be ticked every frame.  You can turn these features
	// off to improve performance if you don't need them.
	PrimaryComponentTick.bCanEverTick = false;

	// ...
}


// Called when the game starts
void UHealthComponent::BeginPlay()
{
	Super::BeginPlay();

	Health = DefaultHealth;

	GameModeRef = Cast<ATankGameModeBase>(UGameplayStatics::GetGameMode(GetWorld()));
	GetOwner()->OnTakeAnyDamage.AddDynamic(this, &UHealthComponent::TakeDamage);

}

void UHealthComponent::TakeDamage(AActor* DamagedActor, float Damage, const UDamageType* DamageType, AController* InstigatedBy, AActor* DamageCauser)
{
	if (Damage == 0 || Health <= 0) { return; }

	Health = FMath::Clamp(Health - Damage, 0.0f, DefaultHealth); //avoid drop health below 0 or above max

	if (Health <= 0)
	{
		if(GameModeRef)
			{
			GameModeRef->ActorDied(GetOwner());
			}
		else
		{
			UE_LOG(LogTemp, Warning, TEXT("Health component has no reference to GameMode"));
		}

	}
}

Thanks a lot.

Aitor

Have you tested various points of the code? e.g. Test OnHit is being called and that it’s making it to ApplyDamage

Hi,

OnHit function is called and works; i tested both

void AProjectileBase::OnHit(UPrimitiveComponent* HitComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit)
{
	AActor* MyOwner = GetOwner();

	if (!MyOwner) { return; }

	if (OtherActor && OtherActor != this && OtherActor != MyOwner)
	{
		UGameplayStatics::ApplyDamage(OtherActor, Damage, MyOwner->GetInstigatorController(), this, DamageType);
		UE_LOG(LogTemp, Warning, TEXT("Damage applied"));
	}

	//play destroy effects

	Destroy();
	UE_LOG(LogTemp, Warning, TEXT("projectile destroyed"));
}

Both appear in output log (also, projectile is destroyed in impact)

Is this logging?

UE_LOG(LogTemp, Warning, TEXT("Health component has no reference to GameMode"));

Nope (so I am assuming health component does exist)

current output is (with turret and tank shooting each other):
LogStats: SubmitErrorReport - 0.000 s
LogStats: SendNewReport - 2.635 s
LogStats: FDebug::EnsureFailed - 3.749 s
PIE: Server logged in
PIE: Play in editor total start time 3.99 seconds.
LogTemp: Warning: Damage applied
LogTemp: Warning: projectile destroyed
LogTemp: Warning: Damage applied
LogTemp: Warning: projectile destroyed
LogTemp: Warning: Damage applied
LogTemp: Warning: projectile destroyed
LogTemp: Warning: Damage applied
(and so on…)

For info: my only difference with original code is i had to include the Add.Dynamic for OnHit on the begin play function as proposed for it to work:

void AProjectileBase::BeginPlay()
{
	Super::BeginPlay();
	ProjectileMesh->OnComponentHit.AddDynamic(this, &AProjectileBase::OnHit);
}

Could you change this log to be

UE_LOG(LogTemp, Warning, TEXT("Damage applied to %s"), *OtherActor->GetName());

And this to be

if(GameModeRef)
{
    UE_LOG(LogTemp, Warning, TEXT("%s has died"), *GetOwner()->GetName());
    GameModeRef->ActorDied(GetOwner());
}
else
{
    UE_LOG(LogTemp, Warning, TEXT("Health component has no reference to GameMode"));
}

Sure;

First change output log when hitting tank or turret:

LogTemp: Warning: Damage applied to BP_PawnTank_C_0
LogTemp: Warning: Damage applied to BP_PawnTurret_2

Second change still does not appear in output log (no message of actor died)

So then that means it’s not reaching past Health <= 0. Have you added logs before that?

Hi again,

I think I solved (but I am not really 100% sure).

As the problem was with TakeDamage function, and OnHit function was the most similar (and was working) only diference between them was that in headed OnHit did have the UFUNCTION() above.

When adding that to TakeDamage function in header, now it does call the function and “A Pawn died” message is shown in log.

I reviewed the videos, and I still do not know why I needed it to work and lecturer did not :man_shrugging:.

Anyway, I will continue now and hope for the best :slight_smile:

Thanks!

EDIT: @Dan, I cannot answer your below post due to the topic being closed

I am talking about TakeDamage Function, not OnHit. I had to put UFUNCTION() in both, Rob only put in on OnHit.

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Sorry I completely forgot to ask about that.

However Rob does have UFUNCTION()

Privacy & Terms