Problem calling custom events from AI behavior tree's task

I have custom events for my two ai characters, RobotShooter and RobotCharger, which are both children of RobotParent and have their own custom event called “AttackPlayer.” My ai behavior tree works perfectly except for a task called “attack” which attempts to cast the owner actor as a RobotShooter then a RobotCharger and call the appropriate “AttackPlayer” custom event which are defined in their own blueprints. These custom events worked as intended when they used onPawnSense instead of being called from the ai behavior tree task. Now they stand still in their idle animations when they see the player. I have no idea what is causing the problem. Relevant screenshots are attached.

1 Like

Hi,

I can’t see anywhere in your blueprints that you set the blackboard key CanSeePlayer to true. I believe this is the reason the Attack task is never reached. Simply go to your AI blueprint and use that PawnSensing component to update this blackboard parameter (Get blackboard > Set Value as Bool; and give it your key name).

I also suggest that you use AIPerception component instead of PawnSensing. The AIPerception is newer and recommended over the PawnSensing.

Hope this resolves your issue.

I have the AIRobotControler use AIPerception to change the CanSeePlayer boolean to true. While looking at the tree when playing I can see that it goes to and from the attack task just fine but stands still instead of doing the custom event AttackPlayer from the character blueprint.

Imgur

Okay, I believe I found where your other problem is. First, in your Attack Task, you’re using Event Receive Execute while you should be using Event Receive Tick! The Receive Execute node works just like Begin Play and will get called only once, as soon as the task starts. Next, you’re calling Finish Execute as soon as your task begins, therefore your task will never do anything! Remove those two nodes, and let the Blackboard key abort this task once the player is out of sight (See under the blackboard condition, it says “abort both”. Upon the blackboard key value change, that selector and its running task will be aborted and your behavior tree will move to the next Selector.

CanSeePlayer is updated off of a call to the event OnTargetPerceptionUpdated in the AIRobotControler. Here’s a screenshot: AIRobotControler Logic - Imgur

I changed what you said but the same thing happens. The tree goes through it’s branches correctly but the Attack task makes the ai character stand still and do nothing. Here’s the updated task: Attack Task Updated - Imgur

Where you have service setting CanSeePlayer? I can find it in your screens or I miss something.

Maybe you have it in other blueprint, but this should be (vision check) as service just after root, then Selectors should be created from Vision service - see or not.

Good. Now your problem narrows down to your Attack task. Before getting to that, do you have a NavMesh in your level? If you do, then start debugging your attack function by first checking whether that very first Cast succeeds. Simply add two separate Print String nodes to each of the cast branches and see which one gets called to verify that the cast succeeds. If it does and you have a NavMesh, then your actor must at least move towards your target!

Here’s another question for you. Why are you saving your player character in a blackboard key and then pass it around? I believe you can directly access your player’s pawn or controller even in your AI blueprint!

Do you have this print strings I see I not see? Just to be sure. As @Vizgin said, I think it should be on tick event. Do another print strings to see Attack Task runs or not (even if not visible).
Also I’m not sure about your state aborts. This confusing me always, but I have for states abort self only and it works as expected.

The abort self will only abort that active Selector and its underlying tasks and will pass the execution to the right Selector. The abort both will not only abort itself but also abort its parent selector and will return the execution to the root node where it will start going down the tree again from left to right.

Hope this clarified the confusion @Vaheva :slight_smile:

Yes, I have a NavMesh and a level to debug in. Using print statements like you suggested, I was able to figure out that the custom event AttackPlayer of neither class is ever called from the attack task because both of the casts failed. Now they stand still and print “failed both casts” while they see the player. Do you know why the casts are failing? Here’s a screenshot of the updated attack task: Attack Task updated 2 - Imgur

Edit: I’m saving the player character in in a blackboard key and passing it to the RobotCharger and RobotShooter blueprints because I didn’t know I could access the player directly. I don’t want to change it right now just so I only change on thing at a time so I know what is broken.

Show me the full AI task blueprint including the variables you defined in it.

There are no other variables or functions defined in that task.

In that case, since both of you’re casts are failing, the only possible cause of it can be referred to your behavior tree getting called by something other than your AI’s. Are you running your behavior tree in your AI’s blueprints? You need to call the “Run Behavior Tree” node through BeginPlay event node in your AI’s blueprints! Please check if you’re doing so for every one of your AI.

I previously had the behavior tree begin onPossessPawn, but I changed it to BeginPlay. Here’s a screenshot: Run Behavior Tree - Imgur. It didn’t change anything and the casts are still failing. RobotCharger and RobotShooter are both children of RobotParent, and all three use the AIRobotBehavior tree.

At this point i have no clue what class of object is being returned from EventReceiveTick’s owner actor wire, so is there any method that prints out what it actually is so I know where it’s comming from?

Try Get Display Name or Get Object Name nodes.

It turns out that wire gives an instance of the AIRobotController. Is there an AIController method that returns the object that it is controlling? I searched in the in editor function search but couldn’t find one. I couldn’t find one in the documentation either.

Based on the information you provided in the comment section, here is a detailed explanation of what was wrong with your code (BP scripts). Simply put, you were violating the polymorphism principles in your code. Polymorphism doesn’t work in the way that you were attempting to do, i.e. it cannot simply cast a Parent class to its children and call their members! Polymorphism requires that you properly design your classes and define their inheritance relationship as well as determine which member functions can be overridden and are therefore virtual! Below is a step by step guide on how to properly use this technique with blueprints and achieve what you want:

  1. Start by creating a parent class blueprint for your AI Pawns. Open its BP editor, create a function and name it Attack. Add any input/output pins that you want! This will be the signature of your Attack function which must be exactly the same for its children in terms of the number of input/output pins and their types. You can also implement the base attack logic that is common between all your AI’s in here. This will reduce the amount of duplicate code that you will be having. You can also leave it blank if you want to!

  2. Using this parent class, create some child BP that will be your AI pawn (If you already have your AI pawn classes, then make sure that they are inheriting from this parent class). Next, open the child’s BP editor, on the left side next to the New Function button, select Override and from the drop-down menu select the Attack function that we created in Step #1 in the parent class. You should get an Event Attack node with the same number of input/output defined in the parent class. Use this event node to implement your AI attack logic.

  3. Now, in order to enable the behavior tree for your AI’s, you must use their AIControllers. Simply go to your AIController, use the BeginPlay node and run the behavior tree you want.

  4. Finally, go to the behavior tree and open the Attack task. Note that since a behavior tree can only be run by a controller, that Other Actor pin in your Event Receive Tick represents the controller that initiated this behavior tree. This controller is your AIController from step #3. Use this Other Actor pin and Cast to your AIController > Get Controlled Pawn > Cast to the Parent BP class > Call Attack function of the parent. That’s it! Since you’ve overridden your parent’s Attack function in its children, the parent will automatically call its children’s Attack function so you wouldn’t have to cast to each of them separately!

There you have it. Polymorphism in Blueprints! Follow these steps exactly as I explained and your AI logic should now work in a much neater and cleaner way.

Hey,

I just wrote you a complete guide in a separate answer on what was causing this issue and how to fix this. Go ahead, read it and let me know if it works :wink:

Thanks. It worked.