Is there a better way to Access another Actor Component in same actor without FindComponentByClass<>()

Hello, i currently on dilemma because i can access another Actor Component using FindComponentByClass<>(), but i’ve checked the source code, it has to performed loops before getting the result. some said that FindComponentByClass is Expensive when used on Event Tick, because i use it on Event Tick also to updating my camera.

Here is the Code :

UCameraMovementComponent::UCameraMovementComponent() // ActorComponent
 {
 	PrimaryComponentTick.bCanEverTick = true;

 	if (AMyCharacter* MC = Cast<AMyCharacter>(GetOwner())) // i wonder if Casting is correct way to access the owner of actor component (in this case). please if you have another alternative i would love to hear that :smiley: 
 	{
 		MyCharacter = MC;
 		Camera = MyCharacter->GetCamera();
 		SpringArm = MyCharacter->GetSpringArm();
 		TraceComponent = MyCharacter->FindComponentByClass<UTraceComponent>(); // this is Actor Component i try to access
 	}
 }

UPrimitiveComponent* UCameraMovementComponent::CurrentTarget() // i want to access Current Target because i set it in TraceComponent/another Actor Component
 {
 	if (TraceComponent)
 	{
 		return TraceComponent->GetCurrentTarget();
 	}
	return nullptr;
}

 bool UCameraMovementComponent::bIsTargetLocked() // same here
 {
 	if (TraceComponent)
 	{
 		return TraceComponent->GetIsTargetLocked();
 	}
 	return false;
 }

i hope my question doesn’t confuses you.
btw i started learning Unreal and C++ in these past 2 months, i’m learning by reading unreal documentation. i’m sorry if i fails to explain my problem. also my english is broken :frowning:

Thank You :smiley:

You could store it as a pointer on the same actor:

UPROPERTY()
  UTraceComponent* TraceComponent = nullptr;

But usually there are better ways to write your code so you don’t have to do that:

  1. Move the logic to update the camera into the component.
  2. Don’t use tick, only use delegates (Observer pattern) to do things just when they are required. Sometimes you have to use tick but usually not.
2 Likes

Hello Roy, Thank you for Replying my question.


Creating a pointer is actually my first attempt, and it gives me an error.
EXCEPTION_ACCESS_VIOLATION reading address 0x00000000000000c8

but here is the weird thing, after i regenerate visual studio project file, i can access it without any problem, but after i write more code to CameraMovementComponent suddenly it gives me the same error EXCEPTION_ACCESS_VIOLATION reading address 0x00000000000000c8


Yeah this is what i try to achieve Roy, i try to think as object oriented to keep things organize.

i only want to access 2 properties from TraceComponent

  • Current Target
  • bIsTargetLocked

Because i need that properties to determine my camera movement and state.

And i don’t know if i can make Camera Component and Spring Arm Component inside CameraMovementComponent, i’ve tried but i can’t move it and no parameter shown inside editor, yeah maybe because it’s Actor Component.


Thank you for mentioning Delegates Roy. this is something i need to learn.


Sorry if i missunderstanding your answer roy, i learn C++ by just making this project, and i learnt a lot while making this project. so much fun doing this, yet so much stress ahaha


1 Like

That’s a null(-ish) pointer exception. You haven’t put anything into the variable.

This is how you would usually do this.

In your MyCharacter.h:

UCLASS()
class YOURPROJECT_API AMyCharacter : public AActor
{
	GENERATED_BODY()

public:
	AMyCharacter();

protected:
	virtual void BeginPlay() override;

public:	
	UFUNCTION(BlueprintCallable)
	void GetTraceComponent();

private:
	UPROPERTY(VisibleAnywhere)
	UTraceComponent* TraceComponent;
};

In your MyCharacter.cpp file:

AMyCharacter::AMyCharacter()
{
	// (other initialization code)

	TraceComponent = CreateDefaultSubobject<UTraceComponent>(TEXT("TraceComponent"));
}

AMyCharacter::GetTraceComponent()
{
	return TraceComponent;
}

In your CameraMovementComponent.cpp:

UCameraMovementComponent::BeginPlay()
{
	Super::BeginPlay();

	AMyCharacter* MyCharacterOwner = Cast<AMyCharacter>(GetOwner());
	UTraceComponent OwnerTraceComponent = MyCharacterOwner->GetTraceComponent();

	// Do something with OwnerTraceComponent here, or store it in a member property.
}

(I wrote that in a text editor without trying compiling it, it might have some errors)

Notice that I’m putting the code to get the owner’s component in BeginPlay(). This is important! You should not put any logic into an object’s constructor other than what is necessary to set up the object and its subobjects. Every C++ class gets initialized on engine init to create their CDOs, and at that time they don’t have owners or anything. The game isn’t even playing at that time.

Putting that code at BeginPlay() will ensure that the code happens actually at runtime when you’re playing your game. In your case you should only have PrimaryComponentTick.bCanEverTick = true; in the constructor and move everything else into BeginPlay().

1 Like

Thank you Ari, Works like a charm.

i already try to make getter before, but it always crashed after the editor loads at 75%.
that because i put logic on the constructor. :disguised_face:

Getter

it’s hard when learning without a teacher. the last solution is asking with the community, if everything i tried gives no results. I love Unreal Engine More…

again, Thank you Ari and Roy for taking your time to answer my question.

3 Likes

My pleasure! Remember to mark this thread as resolved so future answer seekers know to check here if they’re having the same problems.