I cannot access to another class function by using LineTracing

Hey Guys,
I once posted a question a few months ago, but i can’t edit it somehow i am sorry for that. My editor kept crashing and because I had a bad pc it took me like 20 mins to reopen the project so I decided to take a break with ue4, till I get a new PC.

So my question is that I cannot access to another Class from DefaultPawn.
Here is my Code

The exact question is in PControl.cpp as a comment in my code.

PControl.h (Actor Component of DefaultPawn_BP)

#pragma once

#include "Components/ActorComponent.h"
#include "PControl.generated.h"


UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class BPPLAYER_API UPControl : public UActorComponent
{
	GENERATED_BODY()

public:	
	// Sets default values for this component's properties
	UPControl();
	UInputComponent* InputComponent = nullptr;

	// Called when the game starts
	virtual void BeginPlay() override;

	void DoLineTracing();
	
	// Called every frame
	virtual void TickComponent( float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction ) override;

	void DealEDamage();

		
	
};

PControl.cpp

#include "BPPlayer.h"
#include "PControl.h"
#include "EnemyControl.h"


// Sets default values for this component's properties
UPControl::UPControl()
{
	// 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.
	bWantsBeginPlay = true;
	PrimaryComponentTick.bCanEverTick = true;

	// ...
}


// Called when the game starts
void UPControl::BeginPlay()
{
	Super::BeginPlay();
	InputComponent = GetOwner()->FindComponentByClass<UInputComponent>();

	InputComponent->BindAction("Shoot", IE_Pressed, this, &UPControl::DealEDamage);
	
	// ...
	
}

void  UPControl::DoLineTracing()
{
	FVector PViewPoint;
	FRotator PViewRotation;
	FHitResult HitResult;

	GetWorld()->GetFirstPlayerController()->GetPlayerViewPoint(PViewPoint, PViewRotation);

	GetWorld()->LineTraceSingleByChannel(HitResult, PViewPoint, PViewPoint + (PViewRotation.Vector() * 1000), ECollisionChannel::ECC_Visibility);

	AActor* HitActor = HitResult.GetActor();

	if (!HitActor)
	{
		UE_LOG(LogTemp, Warning, TEXT("No HitActor found"));
	}
	else {
		UE_LOG(LogTemp, Warning, TEXT("HitActor found.. Name: %s"), *(HitActor->GetName()));

		/*
			Here I try to call a function from class EnemyControl

			Something like:
			HitActor -> setHealth();

			setHealth() >> simply sets the health -= 10 and logs out current health
		*/
		
		
	}
}


// Called every frame
void UPControl::TickComponent( float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction )
{
	Super::TickComponent( DeltaTime, TickType, ThisTickFunction );

	// ...
}

void UPControl::DealEDamage()
{
	UE_LOG(LogTemp, Warning, TEXT("Shoot is pressed at Location: %s"), *GetOwner()->GetActorLocation().ToString());
	DoLineTracing();
}

EnemyControl.h (Actor Component of an Actor)

#pragma once

#include "Components/ActorComponent.h"
#include "EnemyControl.generated.h"


UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class BPPLAYER_API UEnemyControl : public UActorComponent
{
	GENERATED_BODY()

public:	
	// Sets default values for this component's properties
	UEnemyControl();

	// Called when the game starts
	virtual void BeginPlay() override;
	
	// Called every frame
	virtual void TickComponent( float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction ) override;
	void setHealth();
private:
	int32 health = 100;
	
};

EnemyControl.cpp
// Fill out your copyright notice in the Description page of Project Settings.

#include "BPPlayer.h"
#include "EnemyControl.h"


// Sets default values for this component's properties
UEnemyControl::UEnemyControl()
{
	// 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.
	bWantsBeginPlay = true;
	PrimaryComponentTick.bCanEverTick = true;

	// ...
}


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

	// ...
	
}

void UEnemyControl::setHealth()
{
	health -= 10;
}

// Called every frame
void UEnemyControl::TickComponent( float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction )
{
	Super::TickComponent( DeltaTime, TickType, ThisTickFunction );

	// ...
}

I hope I gave you all the information you need and you can help me. I am new to this and am sitting since hours on that.

I also tried

UEnemyControl* EnemyClass;
EnemyClass->setHealth();

in PControl.cpp when doing Linetrace…
But then it says 'uninitialized local variable EnemyClass used.
When I try to put it in UPROPERT(EditAnywhere) it doesn’t show up anywhere :confused:

I cannot Cast. It says I couldnt cast UClass to UEnemyClass… Idk how to do it.

Are you casting HitActor to UEnemyControl* then trying to access health?

Oh I just noticed, UEnemyControl is a component, not an actor itself. So the best way would be to create a specific actor that has the UEnemyControl blueprint added to it already then do the HitActor cast to that actor’s class and then just grab the UEnemyControl from there.

The problem you are having is “HitActor” is an Actor while UEnemyControl is an ActorComponent.

You need to cast Actor to Actor then get the component of that actor then get the property.

I just created a cube and added actor component “EnemyControl”. But my problem is I dont know any way to get from actorcomponent to the actor itself.
When I use GetOwner () I can’t use the function ‘setHealth ()’ anymore. Can you show me which method I have to use for this pls?

I am unsure of what you are trying to accomplish, so my suspicion is that you are going about this the wrong way. You do’nt go from your component to the actor, you are needing to go from the trace, to the hit actor, to the component.
I would personally make “EnemyControl” an actor itself called “BaseEnemy” not a component. Then I would make children of 'BaseEnemy" for all my various enemy types. This would make the process easier as you would just go:
“Did I hit something? Yes, is it a type of ‘BaseEnemy’? Yes, OK then lets set it’s health.”

Right now it seems like your logic is:
“Did I hit something? Yes, are any of it’s components an ‘EnemyControl’ component? Yes, ok then lets set it’s health.”

This second method would require you to check all the components it has to see if any of them are valid.

I am at work and have some things to attend to this evening, but if I get a chance to make a project to show you I will post it. Let me know if the method I described above would work for you or if you have it as a component for a particular reason so I can make up something as close to your needs as you need.

OH MY GOD, IT FINALLY WORKED!
I thank you so so much, it was confusing me since days and weeks.
What I have done is, like you said, I created a new C++ Class, from type Actor called it ‘EnemyActor’.
Everything I needed was just

AEnemyActor* eActor = Cast<AEnemyActor>(HitActor);

Could you maybe explain to me what Cast excatly does?
I am new to programming and I don’t really understand the definiton of it :confused:

You need to cast. Looks like you figured it out but you wanted to know more about casting so I will put it here so maybe it can help others.

Casting is basically saying “I am looking for this class and expect to find the properties of this class.”

For example lets say you have a base class “Enemy” that is a child class of “Actor” and then “Goblin” and “Minotaur” which are both child classes of “Enemy”.

You wont be modifying the “Actor” class as it is a base unreal class, but you modify “Enemy” class to have the variable “Health”.

This means both “Enemy”, “Goblin” and “Minotaur” will have a variable “Health” because they are parent and children, but “Actor” will not have it because it is the parent of “Enemy” where “Health” is created. We can now define “Goblin” “Health” at a value of 16 and “Minotaur” at a value of 40.

So if you are trying to get the “Health” of any enemy you need to cast to “Enemy” because it has the variable “Health”. Now it will not matter if it is a “Goblin” or “Minotaur” it will still be able to find the variable “Health” but if we try casting from any class other than “Enemy”, “Goblin” or “Minotaur” it would fail to cast and we could not find any variable in it named “Health”. You would find that a “Goblin” would return 16 “Health” and a “Minotaur” would return 40.

Now let’s say our character does bonus damage versus enemies of the class “Minotaur”. We can cast an “Actor” as “Minotaur” and if it is of that class the cast will succeed and if it was a “Goblin” it would fail, even though “Minotaur” and “Goblin” are both children of “Enemy” and grandchildren of “Actor”.

I hope this makes sense. Let me know if you have any more questions and be sure to mark this as answered once you have a satisfactory answer.

thank you man, you really helped me a lot with that.