Best way to compare actors in C++?

— Relevant code in the Character class —

AActor *ASandboxGameCharacter::raycast()
{
	AActor	*actorHit			= nullptr;
	FHitResult *hitResult		= new FHitResult();
	FCollisionQueryParams *cqp	= new FCollisionQueryParams();
	FVector	start				= GetActorLocation();
	FVector	end					= (GetActorForwardVector() * 5000.f) + start;

	if (GetWorld()->LineTraceSingleByChannel(*hitResult, start, end, ECC_Visibility, *cqp)) 
	{
		// For debugging purposes (Draws a visible line in the direction of the raycast)
		DrawDebugLine(GetWorld(), start, end, FColor(255, 0, 0), true);

		if (hitResult->GetActor() != NULL) 
		{
			GEngine->AddOnScreenDebugMessage(-1, 3.0f, FColor::Green, FString::Printf(TEXT("Actor: %s"), *hitResult->GetComponent()->GetName()));
			actorHit = hitResult->GetActor();
		} 
	}
	return actorHit;
}

AActor *ASandboxGameCharacter::returnRaycastActor()
{
	AActor *targetActor = nullptr;

	if (raycast() != nullptr)
	{
		targetActor = raycast();
	}

	return targetActor;
}

*** Please note that the raycast() method is private, hence it acts as a mutator (setter) and returnRaycastActor() acts as an accessor (getter) ***

— Relevant code in Interactable class —

// Defines the behaviour caused by the player when they overlap the props influence cube. 
void AInteractableObject::playerInteraction(UPrimitiveComponent *hitComponent, AActor *interactingActor, UPrimitiveComponent *otherComponent, int32 interactingActorBodyIndex, bool isDetected, const FHitResult & detectionResult)
{
	toggleGlow(true);
	checkingForDirectView = true;
}

// Defines the behaviour caused by the player when they exit the props influence cube.
void AInteractableObject::playerUninteraction(UPrimitiveComponent *hitComponent, AActor *interactingActor, UPrimitiveComponent *otherComponent, int32 interactingActorBodyIndex)
{
	toggleGlow(false);
	checkingForDirectView = false;
}

// Defines the behaviour caused when the player interacts with the prop.
void AInteractableObject::interactImplementation()
{
	if (checkingForDirectView)
	{
		ASandboxGameCharacter *interactingCharacter = Cast<ASandboxGameCharacter>(UGameplayStatics::GetPlayerCharacter(GetWorld(), 0));

		if (interactingCharacter->returnRaycastActor() != nullptr)
		{
			if (interactingCharacter->returnRaycastActor() == UGameplayStatics::GetPlayerCharacter(this, 0))
			{
				Destroy();
			}
		}
	}
}

void AInteractableObject::BeginPlay()
{
	Super::BeginPlay();
}

void AInteractableObject::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

	interactImplementation();
}

If possible, can someone suggest a more appropriate way to compare the actor being hit in the raycast and the interactable objects. Not too familiar with the library definitions, methods and functions, so it would be helpful if someone more knowledgeable/someone who’s been through a similar experience and advise me on what to change. Specifically, the third nested if statement in the “interactImplementation()” method does not work at all, as you’d expect due to it being a strange comparison. The desired behavior was to fetch the type of actor that the object hit in the raycast was and compare it to the interactable actor, which we can then use to identify that the player is directly observing the interactable object. This is entirely my fault, I’m too lazy to sift through tonnes of documentation to find what I need, so I resort to asking others (since I’m relatively new to UE4, and C++ (But I come from Java and Objective-C)). In addition to this, in the initial Character class, I’m using the component attached to the root to cast the ray from. I didn’t really want to do this, instead I wanted to cast from the camera directly, but that was yielding strange results (The source/origin of the cast was different to the position of the camera, hence the vector differed from the expected vector, but the final location was the same). The last thing I think I should mention is that the debug message only shows “StaticMeshComponent0” as the name of the collided mesh, regardless of where you look (Which, btw, is very limited since it’s generated from the character model, thus lacks the ability to freely rotate in the x-axis).

Thanks in advance for any help offered! (Senpai, save me from this hell)

1 Like

I apologize for the code excerpts looking like cancer, the formatting got screwed up when I pasted it into the pop-up window, triggered when pressing the “add code” button, in the editor.

Have you debugged to see where your code fails? You can attach a debugger from VS to the UE4 Editor. it looks like this line may fail since you are comparing an AActor* to a ACharacter*

 if (interactingCharacter->returnRaycastActor() == UGameplayStatics::GetPlayerCharacter(this, 0))

Hey, thanks for commenting. Uh, I already know that this line is incorrect, it’s been left as it is due to it not causing compiler errors, thus I can keep compiling my project files without failure. I wanted to know what the correct comparison would be, in this case. What I wanted to accomplish, instead, was first comparing if the actor detected and the class itself were the same, I then wanted to identify what the static mesh of the actor detected and the class itself were for a final comparison. I know how to obtain this information for the detected actor, but not for the class itself.

Howdy,

If I misunderstood I apologize, but the comparison of actors is the comparison of the pointer to the actor.

For example:

AActor * Ptr = hitResult->GetActor();

(if you where to view the value of Ptr it would be a memory-address, such as “0x00F34C”, this is simply a number representing where the actor is stored in memory).

the this pointer of a actor class is also a pointer, as is any other pointer to an actor.

Note that regardless of type, a pointer is a unique address in memory, that is to say, two different instances of actor objects will have two totally different pointers.
Further, the pointer’s address is not changed by the inheritance of an object, for example:

AMyPlayerClass * Ptr2 = this;
AActor * Ptr3 = Ptr2;
AMyPawnClass * Ptr4 = this;

if(Ptr2 == Ptr3 == Ptr4)
 //This is true, they are all the same object, regardless of inheritance

By this simple logic, I can easily make a comparison between objects with definite certainty!

AActor * ThisPlayer = this;
AActor * Ptr = hitResult->GetActor();
if(ptr == ThisPlayer) TakeSomeAction();
//or in one tine
if(Cast<AActor>(this) == hitResult->GetActor()) TakeSomeAction();

It is worth noting two small things here.
This is not an Unreal mechanism, this is pure C++ and any tutorial on C++ inheritance and pointers will provide you the knowledge you seek.

Secondly, there is absolutely no gaurentee that if an actor is destroyed the memory will not be reused.
For example, if I stored the value of any Ptr variable above, then during my game that object was destroyed, the memory address might be used for another actor, or something totally different.

TL;DR;

An Instance of an Actor is an object, unless you implement something (such as a UUID), the only way to compare the objects would be to compare every property of the Actor.
The Pointer to the Actor however is not the Actor, it is a unique memory-address of where the actor is stored, Compare pointers to get the result you seek.
Many of my students have understood this better if I simply use the analogy of a postal address.
There might be many people with your name in the world, but only you live at your home-address, by the same logic there may be many AActors in the game, but only one exists at a specific memory address.

[Addendum]

If you wish to discover if an object is of a specific type (such as a certain class, you can use IsA, eg:
Ptr1->IsA(AMyPlayerCharacter).

Also, upon re-reading your question I noticed your issue with firing the raytrace from the camera.
I would suggest attaching something to the camera, just in-front of it (such as a USceneComponent), then firing the ray-trace from that.

Hopefully that will help you kōhai!

1 Like

Ah, overlooked that completely. I’m fine with inheritance, but I do sometimes overlook the differences between pointers and variables (did it a lot with this batch, initially…), leading to undesired results. Thanks so much for the comprehensive break down, I’ll adjust my implementation and notify if the behavior result is amended.

NOTE: The method I triggered the raycast event in is a private class, hence you don’t have direct access to hitResult. Instead, the actor hit in the hit result is passed onto a different pointer, which is then returned. That returned value can be accessed using the makeshift accessor method below it, which is what I’m fetching the value from in my implementation.

You are welcome @VDR_Reaper , It’s a common issue when coming from a reference-based language (such as JAVA) into the maelstrom of value-based C++.

Oh, and btw. The raycast issue must have been an engine/editor glitch, as upon remaking the entire project, it hasn’t reoccurred. It’s been flawless, in fact, which is good. Thanks for the advice though! Also, the issue is all within me, I’m just too lazy to realize what I’ve done wrong. I passed Objective-C on the way here from Java, so I’m familiar with C-based programming languages :smiley:

your code is casting this into asandboxgamecharacter, however the function name indicates that this is a AInteractableObject… Is that intentional? is there some kind of relationship between the two?
If not, it may be the issue?

Just me being foolish and trying to access pointer values like variable values, whilst forgetting that their value is a memory address…

There still seems to be an issue with my comparison. The code compiles fine, still, but the desired behavior isn’t achieved. Perhaps my initialization of the interactingCharacter pointer is incorrect for the context?

void AInteractableObject::interactImplementation()
{
	if (checkingForDirectView)
	{
		ASandboxGameCharacter *interactingCharacter = Cast<ASandboxGameCharacter>(UGameplayStatics::GetPlayerCharacter(GetWorld(), 0));

		if (interactingCharacter->returnRaycastActor() != nullptr)
		{
			if (Cast<AActor>(this) == interactingCharacter->returnRaycastActor())
			{
				Destroy();
			}
		}
	}
}

Perhaps I’m doing this stupidly to begin with, would it be better if I compared the static mesh that the object has against the static mesh of the object collided with?

Apologies, I removed the previous comment due to the code being obviously faulty (using “this” incorrectly, hence I’ve attached an amended copy)

I think you are doing so in the correct way, comparing static-meshes and alike adds a layer of complexity that I’d personally avoid.

The code you posted looks to be syntactically correct, and a very-similar implementation works for me?
Assuming your IDE (such as visual studio) can do so, Might I suggest splitting the code into several lines and stepping through each line using the debugger to be certain you are getting what you expect.
ie: that returnRaycastActor() is returning the correct object, etc?

Hmm, well what, ultimately, I wish to accomplish is having a host of interactable objects with different meshes which provide different things when picked up. Now, my plan is to, ofc, never use the interactableObject class, as it’s meant to be the base/parent class for a bunch of child classes (such as PickUps, Dissolvables, Useables/Switches, Moveables). I’m relatively new to UE4, as I said, but I’ve seen that it’s possible to make blueprint iterations of these objects with different static meshes, which is beneficial for what I want to do (multiple different weapon pickups, for example), hence I would need to be detecting what weapon is being picked up when the user is interacting with it, and thus provide the user with that specific item in their inventory. Since I don’t know much about blueprints, I haven’t assumed that I can make a unique identifier within the object blueprints, which I can then use to store the item in an inventory system, appropriately. That’s why I thought (and still do think) it may be beneficial for me to detect and compare SM’s instead. What are your thoughts on this?

I was in the process of splitting up the code and doing the debugging before I left, to ensure everything is receiving and holding the correct values. However, since I got back, I was thinking about making the raycast method a public method, instead, so that I don’t need the accessor method. I’ll just insert a few more breakpoints and see what behavior I’m receiving, for now.

Ok, so within the referenced memory address, “Floor” is also being stored. This should be correct, as I was looking at the floor, but I tried to look directly at the bush prop that I’m using as the static mesh for the interactableObject, which also is storing “Bush” at it’s memory address.

At the first if statement that involves the values for the actors, the returnRaycastActor() method returns: ASandboxGameCharacter::raycast returned 0x0000022fd1fa6800 (Name=0x0000022f902125d0 “Floor”).

Ok, I changed the static mesh to a chair and it works correctly. For some reason, the raycast cannot hit the bush… Interesting.

The workaround, I suppose, would be placing the bush inside an invisible container (that was rectangular) and hitting that instead, thus using it as a surrogate for the bush.