! before a function

Hello, I’m following a tutorial on the EQS system here:

My issue is with the following part of a script:

void AMyAIController::OnPerceptionUpdated(TArray<AActor*> UpdatedActors)
{
	//If our character exists inside the UpdatedActors array, register him
	//to our blackboard component
 
	for (AActor* Actor : UpdatedActors)
	{
		if (Actor->IsA<AEqsTutCharacter>() && !GetSeeingPawn())
		{
			BlackboardComp->SetValueAsObject(BlackboardEnemyKey, Actor);
			return;
		}
	}
 
	//The character doesn't exist in our updated actors - so make sure
	//to delete any previous reference of him from the blackboard
	BlackboardComp->SetValueAsObject(BlackboardEnemyKey, nullptr);
}

AActor* AMyAIController::GetSeeingPawn()
{
	//Return the seeing pawn
	UObject* object = BlackboardComp->GetValueAsObject(BlackboardEnemyKey);
 
	return object ?  Cast<AActor>(object) : nullptr;
}

I’m quite new to C++ and I’m having trouble figuring out what’s going on here. To me, it looks like GetSeeingPawn() checks to see if the Blackboard key is storing an object, and if it is storing a valid object, it tries to cast that to an AActor class, or otherwise it returns nullptr.

However, I’m not really sure what " && !GetSeeingPawn()" would mean. As I currently imagine it, this is equivalent to, “&& GetSeeingPawn == nullptr”. So the whole “if” statement is saying, “if the actor is this particular type of character, and the Blackboard key is empty, assign this actor to the Blackboard key”.

However, I don’t understand the following line, because if GetSeeingPawn() doesn’t return a nullptr (i.e. if there’s something stored there already), we fail to assign anything to the key, and we fail to return, and instead we just move out of the “for” loop and go on to set whatever was in there to nullptr. That would seem bad to me, as we’d be setting the Blackboard Key to nullptr every second time we ran OnPerceptionUpdated.

I feel like I’m misunderstanding something, but I’m not sure what.

if( GetSeeingPawn()) with out the ! means true, with the ! means is it a false. So when you see the ! that means NOT. ! = NOT, or false.
that says if the actor is that class and the !GetSeeingPawn() is false, then you can drop into that if.
It not setting it to nulptr it is just checking what is it, true or false and if its a nullptr it is a false then it will drop in. So if you have a seeing pawn then it will be true and you will not get in because both are not true in that if statement to let you into it.

Here is one you can use, off and on thru your code when you need it.

Example the bool

//Takes a bool and turns it to its opposite 
 bIsThisTrue =  !bIsThisTrue ;//If it true coming in it will be false going out or vise versa.

Hope this helps.

Hello, I agree with what you’ve said, but this doesn’t fully answer my question.

My problem is this:

From what I understand, if we DO have a pawn already assigned to the Blackboard Key, then GetSeeingPawn() returns true (so !GetSeeingPawn() never applies, we don’t reach the return, and so we then go onto the next line, which sets the Blackboard Key to nullptr.

So the first time we run OnPerceptionUpdated() we’d assign an Actor to the key, then the second time we run it, we’d set the key to nullptr, then the third time we’d set it to an Actor, etc.

Do you agree this is what the code is doing, or have I missed something?

add this see what it is

GEngine->AddOnScreenDebugMessage(-1, 5.1f, FColor::Green, FString::Printf(TEXT("GetSeeingPawn is a %s"), *this->GetSeeingPawn()));

It is basically scanning all actors and if those 2 things go true you assign whatever that blackboard is and return out of the function and go no farther thru it. If its false it goes until all fors are done then goes to bottom line and finishes, but if you get a true in there anywhere thru the for it will enter set whatever that is and return(break out) and that function is done until called again.

If you used a break enstead of a return it would run the last line when it went true. If you needed that.

This line says this, if object is an actor its true use that if it not and its false use the nullptr.

   return object ?  Cast<AActor>(object) : nullptr;

I know all this. But it still doesn’t make sense to me. The first time we run OnPerceptionUpdated, !GetSeeingPawn() isn’t going to return an actor because nothings assigned to the key, so when we go through the FOR loop, we’ll expect to fulfill both conditions there and set the Blackboard key to one of the Actors.

However, the second time we run through OnPerceptionUpdated(), GetSeeingPawn() will return the Actor that we set the first time via the Blackboard key. Because of this, !GetSeeingPawn() won’t be fulfilled as a condition, and we will never return early. Instead, we’ll finish cycling through the “for” loop, and go straight on to the next line, where we set the Blackboard key to nullptr.

If I’m wrong about that, please explain what I’ve got wrong. My point is that I would expect this code to set the Blackboard key the first time it runs, then set it to nullptr the second time, etc.

did you write this or is this epics code? Then i will know how i need answer you.

your conmment

//If our character exists inside the UpdatedActors array, register him
//to our blackboard component

If that is what you are after take the ! off. Then when it finds the actor your after it will add it. Right now your checking if its a nullptr then add it. I think you want it added when its your characters actor right? if so take the ! out of the if.

I’m following along with the tutorial that I posted at the top of this thread. If you follow that link to the tutorial, you can hopefully see where I’m copying the code from (the second code block on that page).

I agree with your assessment that this code looks rather suspicious. GetSeeingPawn()'s return isn’t going to change based on anything inside that loop. The code doesn’t exactly match what it’s comments say, either.

I believe you are right, that the first perception update from one of these characters would set the blackboard key, and then the next perception update that includes one of these characters would then null the blackboard key.

That behavior does sound very suspiciously weird. It’s one of those things that is either so brilliant that I am completely missing the point, or it doesn’t do what the author thinks/says it does.

1 Like