OnClicked not working in C++(works in bp)

Hi,

I was trying to use OnClicked function to detect whether an actor is being clicked.
Like this:

83335-cube.png

When I click this cube, it will change its boolean variable isSelected to true.
So I have a pawn class and a player controller class. But same thing works in blueprint not in the C++.

This is my pawn class, as you see, very simple. isSelected should change to true once the pawn is clicked.

// Sets default values
ABasicPawn::ABasicPawn()
{
	PrimaryActorTick.bCanEverTick = true;
	OnClicked.AddDynamic(this, &ABasicPawn::selected);
}
//Begin play, tick and setup input component remains unchanged.
void ABasicPawn::selected()
{
	isSelected = true;
}

This is my c++ controller class, only the constructor is modified and nothing else:

AUserController::AUserController()
{
	bShowMouseCursor = true;
	//DefaultMouseCursor = EMouseCursor::Crosshairs;
	bEnableClickEvents = true;
	bEnableMouseOverEvents = true;
}

So I constructed another player controller with same property using blueprint and it works fine, isSelected becomes true from pawn class so I think there is no problem in my pawn class.

82232-1.png

But aren’t the blueprint and C++ class same here? I am wondering what is the extra stuff blueprint does because both the C++ code and Blueprint script changes same properties. And what should I add in the C++ file?

Thanks!

1 Like

I had a similar problem a while back: Sprite click events not firing - Asset Creation - Epic Developer Community Forums

In my case, I’d been doing extra stuff while setting up the actor I was attempting to click that caused it not to recognize the click events. In the end, all I needed was to remove the extra stuff and keep the click-registration:

OnClicked.AddUniqueDynamic(this, &ATerrainTile::OnClicked_Mouse);

Please also note that you (evidently) need to watch for click events on the actor you are trying to click, not the one the player is controlling.

Another possibility I recall was that a bunch of other answers suggested that not having collision components can cause this sort of issue too. If you’re not sure, you can test by creating a blueprint class that inherits from your C++ class, and adding a (e.g.) Box Collision component using the Add Component button.

83266-boxcollision.png

If neither of those help, we may need additional information to help. More of the code from the actor you are trying to click would probably be most important. The code from the constructor and the BeginPlay method is likely the best place to start.

In any case, please let me know if this helps.

Hi , thanks for your reply. I read your question page and checked my mine. And I updated my description so you can see that there is only one onclicked event and a function to change a boolean in my pawn class. This pawn class is not the one I am controlling and it is just a simple cube. I tried to add it with a box collision and nothing happens.

But the pawn class worked with the blueprint class with or without the box collision. So I am guessing the problem is in the C++ controller side. Like what you said in your problem, there should be some setup that has done by blueprint by default. Maybe just one line of code, but I have no clue what it should be.

Hi bwhhy,

I just put together a quick test and everything worked correctly. Perhaps the steps I used will help you:

  1. Launch UE 4.10.4; Create a new C++ project with Basic Code, Desktop/Console, Maximum Quality, and No Starter Content
  2. Add a Player Controller C++ class and use the default constructor so show the mouse cursor, and enable click and mouse-over events
  3. Open the C++ Game Mode class that was generated with the project and use the default constructor to set the default Player Controller class to my new class
  4. Edit the Project Settings to use the C++ Game Mode class (Maps & Modes → Default Modes → Default GameMode)
  5. Add a new Pawn C++ class with a click function that simply logs a message to the output log and registers that function in the default constructor
  6. Add a blueprint class derived from my C++ Pawn class and add a cube to its components
  7. Place one of my blueprint Pawns into the scene in front of the player
  8. Play the level, click the cube of my blueprint Pawn class, view the Output Log and see that the message appeared

Here are some highlights from the code in my test:

From the C++ Player Controller class (*.h):

public:
    AMyPlayerController();

(*.cpp):

AMyPlayerController::AMyPlayerController()
{
    bShowMouseCursor = true;
    bEnableClickEvents = true;
    bEnableMouseOverEvents = true;
}

From the (generated) C++ Game Mode (*.h):

public:
    AUEA389222GameMode();

(*.cpp):

AUEA389222GameMode::AUEA389222GameMode()
{
    PlayerControllerClass = AMyPlayerController::StaticClass();
}

From the C++ Pawn class (*.h):

public:
    // ...
    UFUNCTION()
    void OnSelected();

(*.cpp):

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

    OnClicked.AddUniqueDynamic(this, &AMyPawn::OnSelected);
}

void AMyPawn::OnSelected()
{
    UE_LOG(LogTemp, Warning, TEXT("Pawn selected"));
}

Hey ,
Sorry for this long xD, was having a holiday. Thanks for your code! I compared mine and yours and I finally found this part: UFUNCTION, I didn’t add this with my pawn class selected function.

UFUNCTION()
void selected();

And when I add it, it worked.

Great! Finally!

But, this gives me several question here, the first is why? What’s the mechanic behind that the UFUNCTION identifier is necessary here?

The second question is if I don’t add UFUNCTION identifier, it will still work if it is called by a blueprint controller(not work if it’s called by a C++ controller). Do you have any idea what’s the magic of blueprint here?

Anyway, thanks bro!

Glad to help! And I hope it was an excellent holiday!

To answer your questions, I’m not positive – I’m fairly new at some of that stuff. I can give a couple theories though:

For the first question:
The UFUNCTION() identifier is a macro used in compilation to allow Unreal to see and use more information about the function. I don’t know all the details, but I’ve noticed the engine doesn’t always notice functions that don’t use the UFUNCTION() macro. The phrase “reflection system” is often used in conjuction with these macros, but I don’t know much about that yet.

I think the more important part has to do with the click registration. It seems to require that the handlers you use are UFUNCTIONs. I assume it has to do with the mechanic used internally to call the function when the click actually happens. Unfortunately, I haven’t found the details of that mechanism so I can’t speculate much further.

If I recall correctly, when you try to register a non-UFUNCTION for click-handling (or other similar actions), you’ll see a message in the output log that indicates the issue. I don’t recall the exact phrasing, but you could try it if you like.

As for the Blueprint vs. C++ issue:
Can I presume that the Blueprint version is pure-Blueprint without any C++ functions in the pawn? If that is the case, I know the Blueprint stuff (editor and compiler-equivalent in particular) does a lot of work for us. I’d imagine it knows the “function” (event, if I recall the terminology) that handles the click needs certain identifiers and so adds them invisibly.

If the pawn still uses some C++ code even when working primarily with Blueprints, there’s another possibility that has to do with how the Blueprint code invokes C++ functions. That’s seriously speculative on my part though, and wouldn’t be my first bet.

Thanks! Yeah, For the second one, the pawn is pure C++ and it worked successfully if being invoked by a blueprint controller so I think the invoking method of blueprint should be the reason. Guess we will understand it more in the future, lol, thanks man.

For anyone running into this in the future, the problem was that the click-handling function was not marked as a UFUNCTION().

To fix it, all you need to do is add the UFUNCTION() macro just before you declare the function in your class (inside the *.h file). For example:

public:
    // ...
    UFUNCTION()
    void OnSelected();

Why I can bind the onlick in begin play but not in constructor…
i am soooo confused…