x

Search in
Sort by:

Question Status:

Search help

  • Simple searches use one or more words. Separate the words with spaces (cat dog) to search cat,dog or both. Separate the words with plus signs (cat +dog) to search for items that may contain cat but must contain dog.
  • You can further refine your search on the search results page, where you can search by keywords, author, topic. These can be combined with each other. Examples
    • cat dog --matches anything with cat,dog or both
    • cat +dog --searches for cat +dog where dog is a mandatory term
    • cat -dog -- searches for cat excluding any result containing dog
    • [cats] —will restrict your search to results with topic named "cats"
    • [cats] [dogs] —will restrict your search to results with both topics, "cats", and "dogs"

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)

Product Version: UE 4.19
Tags:
more ▼

asked Jun 25 '18 at 03:43 PM in C++ Programming

avatar image

VDR_Reaper
13 2 6 9

avatar image VDR_Reaper Jun 25 '18 at 03:45 PM

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.

avatar image HarryHighDef Jun 26 '18 at 09:28 AM

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))

avatar image VDR_Reaper Jun 26 '18 at 10:24 AM

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.

(comments are locked)
10|2000 characters needed characters left
Viewable by all users

1 answer: sort voted first

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!

more ▼

answered Jun 26 '18 at 11:50 AM

avatar image

DarthPJB
251 2 5 6

avatar image VDR_Reaper Jun 26 '18 at 01:15 PM

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.

avatar image DarthPJB Jun 26 '18 at 01:18 PM

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++.

avatar image VDR_Reaper Jun 26 '18 at 01:24 PM

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 :D

avatar image VDR_Reaper Jun 26 '18 at 01:36 PM

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

avatar image VDR_Reaper Jun 26 '18 at 01:45 PM

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();
             }
         }
     }
 }
avatar image VDR_Reaper Jun 26 '18 at 01:46 PM

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?

avatar image DarthPJB Jun 26 '18 at 02:00 PM

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?

avatar image VDR_Reaper Jun 26 '18 at 02:48 PM

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?

avatar image DarthPJB Jun 26 '18 at 03:22 PM

Might I recommend creating an actorComponent class, this type is effectively code that you can "bolt onto" any actor in it's blueprint/c++. It doesn't have any display mesh, but allows you to add functionality.

I use a similar system in a game i am developing. all intractable objects have a "GameObjectComponent" added, when I trace something I check if it has such a component and proceed to call "interacted" on that part.

I'd provide a code-sample, but i'm away from my codebase at the moment.

avatar image VDR_Reaper Jun 26 '18 at 03:50 PM

Haha, I was working on implementing something similar to that (a modular component class that allows me to perform checks and expand the functionality of related classes without modifying the base classes) before I came here to seek help. That's exactly what I wanted to achieve with it, too. No need to provide such a sample, thanks for all the help you've already given me.

avatar image DarthPJB Jun 26 '18 at 04:53 PM

You are very welcome :)

avatar image VDR_Reaper Jun 26 '18 at 02:54 PM

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.

avatar image VDR_Reaper Jun 26 '18 at 03:09 PM

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.

avatar image VDR_Reaper Jun 26 '18 at 03:16 PM

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

avatar image VDR_Reaper Jun 26 '18 at 03:17 PM

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

avatar image VDR_Reaper Jun 26 '18 at 03:19 PM

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.

avatar image DarthPJB Jun 26 '18 at 03:23 PM

I Belive brushes work somewhat differently in the engine.

avatar image VDR_Reaper Jun 26 '18 at 04:13 PM

Hmm, how so? Because the default arrows, door and the bush aren't detected in the raycast, regardless of where you look. I've looked everywhere and they still aren't detected. It continues to show the "StaticMeshComponent0" as being hit. Whereas, when a chair is hit it shows "InteractableMesh".

avatar image VDR_Reaper Jun 26 '18 at 04:17 PM

Also, for some reason the value stored as the actor in both the interactable class and the hitResult is "Bush", even thought it's now a chair?

avatar image VDR_Reaper Jun 26 '18 at 03:20 PM

This is actually quite irritating, as my original code actually works correctly this way (code I had prior to creating this post)… Thanks for all the help!

avatar image VDR_Reaper Jun 26 '18 at 01:50 PM

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

(comments are locked)
10|2000 characters needed characters left
Viewable by all users
Your answer
toggle preview:

Up to 5 attachments (including images) can be used with a maximum of 5.2 MB each and 5.2 MB total.

Follow this question

Once you sign in you will be able to subscribe for any updates here

Answers to this question